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:
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.
POST /api/extract
Two body shapes. A URL as JSON:
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:
curl -X POST https://extract.ounie.com/api/extract \ -H "Authorization: Bearer xtr_live_..." \ -F file=@report.pdf \ -F format=markdown
The response is the document:
{
"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.
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
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.
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
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.
{
"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_…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.
# 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"}'The network is named base, not eip155:8453 — the naming scheme selects the protocol version, and this endpoint speaks x402 v1.
Limits & retention
Out of credits? Top up at ounie.com/dashboard/settings. There is no plan to upgrade — Extractor has no plans.