Developer docs

API quickstart

One endpoint in, typed fields out: POST /api/v1/extract returns every field as {value, type, confidence, p_null} plus a document-level needs_review flag. Three steps below — the curl example runs as-is once you have a key.

1 · Get an API key

1Free tier — instant key

1,000 extractions per UTC calendar month, no card:

curl -X POST https://extract.redsugartree.com/api/v1/signup \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com"}'

Returns {"api_key":"eex_free_…","plan":"free","quota":1000}. Save it — the key is shown only once. Lost it? POST /api/v1/reveal-key with the same email gets it back (3 requests/hour/IP).

2Paid tier — buy, then reveal

Checkout on the pricing page ($9 Starter / 10K, $29 Pro / 100K). After payment confirmation, fetch your key with the purchase email:

curl -X POST https://extract.redsugartree.com/api/v1/reveal-key \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com"}'
Didn't get the activation email? Paid checkouts email your key from keys@extract.redsugartree.com right after payment. If it never lands (spam folder, typo'd address), don't wait — the reveal-key command above gets the same key with your purchase email (3 requests/hour/IP).

2 · Call the extract endpoint

3Send a document, get typed fields

Auth: Authorization: Bearer <key> (or X-API-Key: <key>). Exactly one of text / image_b64 / file_url in input. This example ships with the repo — copy, swap the key, run:

curl -X POST https://extract.redsugartree.com/api/v1/extract \
  -H "Authorization: Bearer eex_free_REPLACE_ME" \
  -H "Content-Type: application/json" \
  -d '{"doc_type":"invoice","input":{"text":"INVOICE INV-2291\nVendor: Acme Ltd\nInvoice date: 2026-11-01\nDue date: 2026-11-30\nCurrency: USD\nLine items:\n- Design retainer (Nov 2026): 1000.00\n- Extra revisions: 80.00\nTax: 0.00\nTotal due: 1080.00"}}'

200 response (real field names, real contract):

{
  "doc_type": "invoice",
  "data": {
    "total":       { "value": 1080.00, "type": "number", "confidence": 0.98, "p_null": 0.01 },
    "tax":         { "value": 0.00,    "type": "number", "confidence": 0.95, "p_null": 0.04 },
    "currency":    { "value": "USD",   "type": "text",   "confidence": 0.99, "p_null": 0.00 },
    "vendor":      { "value": "Acme Ltd", "type": "text", "confidence": 0.99, "p_null": 0.00 },
    "invoice_date":{ "value": "2026-11-01", "type": "date", "confidence": 0.97, "p_null": 0.02 },
    "due_date":    { "value": "2026-11-30", "type": "date", "confidence": 0.96, "p_null": 0.03 },
    "line_items":  { "value": [ { "description": "Design retainer (Nov 2026)", "amount": 1000.00 },
                                { "description": "Extra revisions", "amount": 80.00 } ],
                     "type": "list", "confidence": 0.94, "p_null": 0.05 }
  },
  "needs_review": false,
  "truncated": false,
  "usage": { "tokens_in": 655, "cost_usd": 0.0000655 },
  "generated_by": "ai"
}

Request reference

Body fieldTypeNotes
doc_typestringinvoice | receipt | contract | ticket | custom (required)
inputobjectExactly one of text (string), image_b64 (base64 image), file_url (http/https, 10s fetch; PDF only with a text layer)
schemaobjectRequired only for doc_type=custom: {"fields":[{"name":"…","type":"number","required":true,"hint":"…"}]}. Ignored for built-in types.
options.confidence_thresholdnumber 0–1Default 0.7. A field below it (or with p_null > 0.3) sets needs_review=true.
options.return_rawbooleanDefault false. When true, the raw model output is attached as raw.

Input rules

Rate limits

10 requests/second sustained per key with a burst of 20. Over the limit → 429 rate_limited with a Retry-After header. Limits are enforced per key; different keys never affect each other. A free-tier edge firewall rule (Bot Fight Mode + WAF rate limiting on /api/*) backs this up.

Error codes

Every error uses the same body: {"error":{"code":"…","message":"…"}}.

HTTPcodeWhen
401invalid_api_keyMissing, invalid or revoked key. The response never reveals which.
402quota_exceededMonthly quota reached, or subscription not active (error.reason = subscription_inactive; paid responses carry X-Subscription-Status).
422invalid_request + sub-codesSee table below.
429rate_limitedPer-key rate limit exceeded (Retry-After header set).
500internal_errorUnexpected server error (no stack traces leaked).
502upstream_unavailableExtraction model failed after 2 retries — retry later, quota untouched.

422 sub-codes

codeCause
invalid_requestBad JSON, unknown doc_type, more than one (or zero) input keys, bad options.
input_too_largeBody > 2 MB.
missing_schemadoc_type=custom without a schema.
invalid_field_typeCustom field type outside text/number/date/datetime/list/boolean.
too_many_fields / invalid_field_name / duplicate_field_name / invalid_schemaCustom schema shape violations (≤30 fields; names match [a-zA-Z_][a-zA-Z0-9_]*).
invalid_confidence_thresholdoptions.confidence_threshold outside 0–1.
invalid_file_urlNon-http(s) URL, fetch failure or timeout (>10s).
unsupported_inputUnsupported content type from file_url, or a PDF without an extractable text layer.

Built-in schemas

invoice 7 fields

fieldtypereq
totalnumberyes
taxnumber
currencytextyes
vendortextyes
invoice_datedate
due_datedate
line_itemslist

contract 6 fields

fieldtypereq
party_atextyes
party_btextyes
effective_datedate
term_monthsnumber
valuenumber
renewal_datedate

receipt 5 fields

fieldtypereq
totalnumberyes
taxnumber
merchanttextyes
datedateyes
categorytext

ticket 5 fields

fieldtypereq
requestertext
prioritytext
created_atdatetime
sla_duedatetime
summarytextyes
Custom schemas use the same 6 types (text, number, date, datetime, list, boolean) — up to 30 fields, names matching [a-zA-Z_][a-zA-Z0-9_]*. Send doc_type:"custom" plus your schema.

Custom schema example

doc_type=custom with a two-field schema — the response contains exactly the fields you declare:

curl -X POST https://extract.redsugartree.com/api/v1/extract \
  -H "Authorization: Bearer eex_free_REPLACE_ME" \
  -H "Content-Type: application/json" \
  -d '{
    "doc_type": "custom",
    "schema": {
      "fields": [
        { "name": "po_number",  "type": "text",   "required": true, "hint": "Purchase order number" },
        { "name": "amount_due", "type": "number", "required": true, "hint": "Total amount due" }
      ]
    },
    "input": { "text": "PO-4471\nVendor: Acme Ltd\nAmount due: 2400.00 USD" }
  }'

Response shape (same contract as the built-ins, only your two fields):

{
  "doc_type": "custom",
  "data": {
    "po_number":  { "value": "PO-4471", "type": "text",   "confidence": 0.97, "p_null": 0.02 },
    "amount_due": { "value": 2400.00,   "type": "number", "confidence": 0.95, "p_null": 0.03 }
  },
  "needs_review": false,
  "truncated": false,
  "usage": { "tokens_in": 128, "cost_usd": 0.0000128 },
  "generated_by": "ai"
}

Pricing

PlanPriceExtractionsQuota window
Free$01,000 / monthUTC calendar month
Starter$9 / month10,000 / monthSubscription period (resets on each renewal)
Pro$29 / month100,000 / monthSubscription period (resets on each renewal)

Only successful 200 responses consume quota. 4xx/5xx never do. Running out → 402 quota_exceeded, never a silent downgrade. All tiers include confidence + p_null on every field.

All endpoints

EndpointAuthPurpose
POST /api/v1/extractAPI keyExtract typed fields from a document
POST /api/v1/signup—Issue a free key for an email (5 req/hour/IP)
POST /api/v1/reveal-key—Retrieve the key for an email (3 req/hour/IP)

Questions? support@redsugartree.com · Back to the homepage

Terms of Service · Privacy policy · Refund policy · Contact