extractor

API docs

One endpoint, one document, 2 credits. Base URL https://extract.ounie.com. JSON everywhere, synchronous — there is no job to poll.

Authentication

Mint a key at /dashboard/api-keys (up to 5 active). Send it as a bearer token:

header
Authorization: Bearer xtr_live_…

Clients that can't set headers — including the Ounie AI Team's manual MCP entries — may pass ?api_key=xtr_live_… on the URL instead. Your ounie.com master key (ounie_live_…) also works once you enable "Use across Ounie apps" in your ounie.com settings. Browser sessions on this domain are authenticated by the shared Ounie cookie, so the dashboard uses the very same endpoints.

A key spends only its owner's credits, and a call is refused with a 402 before it can overdraw. An agent holding your key can spend what you have — never more.

POST /api/extract

Two body shapes. A URL as JSON:

url.sh2 credits
curl -X POST https://extract.ounie.com/api/extract \
  -H "Authorization: Bearer xtr_live_..." \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/report","format":"markdown"}'

Or a file as multipart:

file.sh2 credits
curl -X POST https://extract.ounie.com/api/extract \
  -H "Authorization: Bearer xtr_live_..." \
  -F file=@report.pdf \
  -F format=markdown
FieldTypeNotes
urlstringhttps URL of a page or a document file. JSON body only.
filebinaryMultipart only. Up to 20MB.
formatstringmarkdown (default) · text · json
schemaobjectRequired for format:"json". JSON Schema or a plain example object.
promptstringOptional steer for the JSON pass — e.g. which section to read.

The response is the document:

200 OK
{
  "ok": true,
  "id": "9f3c…",                      // fetch again free at /api/extractions/9f3c…
  "format": "markdown",
  "doc_type": "pdf",
  "source": { "kind": "file", "url": null, "filename": "report.pdf" },
  "metadata": {
    "title": "Q3 Board Report",
    "author": "Finance",
    "pages": 12,
    "billed_pages": 12,               // pages that carried text — what you paid for
    "words": 4210,
    "chars": 26188,
    "lang": "en"
  },
  "markdown": "# Q3 Board Report\n…",
  "text": "Q3 Board Report\n…",
  "credits": { "quoted": 2, "charged": 2, "refunded": 0 }
}

Reading it again

Both of these are free — you already paid for the document.

reads.sh0 credits
GET /api/extractions             # your history + totals
GET /api/extractions/<id>        # one document, body included
GET /api/extractions/<id>?as=markdown   # raw .md, no JSON envelope
GET /api/extractions/<id>?as=text
GET /api/extractions/<id>?as=json       # the structured result only

GET /api/credits                 # spendable Ounie credits
GET /api/pricing                 # public — no auth

Formats

formatYou getGood for
markdownHeadings, lists, tables and fenced code preserved.Feeding a model; chunking with real boundaries.
textThe same document with the syntax removed.Embeddings, search indexes, diffing two versions.
jsonAn object matching your schema, plus missing_fields.Pulling the same fields out of many documents.

markdown and text are both returned every time, whichever you asked for — the text is a projection of the markdown, so there is no reason to make you pay twice for it.

Structured JSON

Fields are filled ONLY from text present in the document. Anything the document does not state comes back null and its name appears in missing_fields. Nothing is inferred from general knowledge — an extractor that invents a plausible total is worse than one that returns nothing.

json.sh
curl -X POST https://extract.ounie.com/api/extract \
  -H "Authorization: Bearer xtr_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/invoice",
    "format": "json",
    "schema": { "invoice_number":"string","total_usd":"number","due_date":"string" }
  }'

Errors

StatuserrorMeaning
400audio_video_not_supportedSpeech is billed per minute, not per document — use https://transcribe.ounie.com.
400unsupported_file_typeNo parser for that extension.
400schema_requiredformat:"json" without a schema.
401unauthorizedNo session, no bearer key, no ?api_key.
402insufficient_creditsIncludes required_credits, balance_credits and buy_credits_url.
413file_too_largeOver 20MB.
422thin_resultNothing extractable. Fully refunded, no ledger row.
422pdf_unreadableThe file is corrupt or encrypted.
503extraction_unavailableOurs, not yours. Nothing charged; retry shortly.
Every failure path refunds before it returns. If you see an error, the credits are already back — there is nothing to reconcile.

MCP server

Streamable HTTP at /api/mcp (legacy SSE at /api/sse). Works with Claude, Cursor, ChatGPT, the AI SDK and the Ounie AI Team.

mcp config
{
  "mcpServers": {
    "extractor": {
      "url": "https://extract.ounie.com/api/mcp",
      "headers": { "Authorization": "Bearer xtr_live_…" }
    }
  }
}

// Hosts that can't set static headers (the Ounie AI Team's manual
// HTTP entry among them) put the key in the URL instead:
// https://extract.ounie.com/api/mcp?api_key=xtr_live_…
ToolCostWhat it does
extract_document2 crURL → markdown, text or schema-shaped JSON.
get_extractionfreeFetch a document you already extracted.
list_extractionsfreeYour history, newest first.
get_credit_balancefreeSpendable credits + how many documents that buys.
get_pricingfreePublic — no authentication needed.
whoamifreeWhich account this key belongs to.

A tool call that would overdraw is refused with insufficient_credits and a link to top up — it never partially runs. Very large documents are clipped in the tool response and fetched in full with get_extraction, which is free.

x402 — pay per call, no account

For agents with a wallet and no Ounie login. $0.024 in USDC on Base per document.

x402.sh$0.024 USDC
# 1. ask
curl -X POST https://extract.ounie.com/api/x402/extract \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/report"}'

# → 402
{ "x402Version": 1,
  "accepts": [{ "scheme":"exact", "network":"base",
                "maxAmountRequired":"24000",
                "payTo":"0x…", "asset":"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
                "extra": { "name":"USD Coin", "version":"2" } }] }

# 2. sign the authorization, retry with the header
curl -X POST https://extract.ounie.com/api/x402/extract \
  -H "X-Payment: <base64 payload>" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/report"}'
Payment is verified before the work and settled after it. A settlement on chain is final and has no refund path, so a document with no extractable text — or one longer than the single 50-page block you signed for — is refused before any USDC moves. An oversized document comes back as a fresh 402 quoting the real price.

The network is named base, not eip155:8453 — the naming scheme selects the protocol version, and this endpoint speaks x402 v1.

Limits & retention

Value
Price2 credits per 50-page block
Upload size20MB
Supported.pdf .docx .pptx .xlsx .html .htm .txt .md .markdown .csv .png .jpg .jpeg .webp .gif
Not supportedaudio & video → https://transcribe.ounie.com
Active keys5 per account
RetentionLong document bodies are deleted after 30 days; metadata is kept
Timeout300s (a rendered page or a long PDF can take up to a minute)

Out of credits? Top up at ounie.com/dashboard/settings. There is no plan to upgrade — Extractor has no plans.