API docs

Research Desk for agents

Three rails, one behaviour: submit a question, get back a brief in which every claim carries the indices of sources that were actually fetched. Unsupported claims never ship, and a brief with nothing traceable is refunded rather than delivered.

REST

Every route accepts the shared .ounie.com session cookie or a bearer key — in the Authorization header, or as ?api_key=for clients that cannot set headers. Calls draw the key owner’s Ounie credits and can never overdraw: a short wallet gets 402 before anything upstream runs.

Run a brief

POST https://research.ounie.com/api/briefs
Authorization: Bearer rsd_live_…
Content-Type: application/json

{
  "question": "What changed in EU AI Act enforcement in 2026?",
  "depth": "standard",             // quick | standard | deep  (default standard)
  "recencyDays": 180,              // optional, 1–3650
  "domains": ["europa.eu", "-reddit.com"],   // '-' excludes; max 20
  "format": "both"                 // markdown | json | both   (default both)
}

→ 202 Accepted
{
  "id": "…",              "status": "queued",
  "eta_seconds": 60,      "credits_reserved": 35,
  "poll_url": "https://research.ounie.com/api/briefs/…"
}

A brief runs immediately in the background; a cron sweeps anything the inline runner never started, so a dropped connection costs latency, not money. Up to 5 briefs may run at once per account.

Poll or read one

GET https://research.ounie.com/api/briefs/{id}      # free — a read of paid work
GET https://research.ounie.com/api/briefs           # ?status=&limit=&offset=
DELETE https://research.ounie.com/api/briefs/{id}   # abort (refunds) or delete

Polling costs nothing and also nudges a queued brief into running, so a caller that polls is its own backstop.

MCP server

One endpoint serves Streamable HTTP and legacy SSE. Works with Claude, Cursor, ChatGPT, the AI SDK, and the Ounie AI Team, whose manual HTTP entries cannot set static headers — so the key rides in the URL instead.

https://research.ounie.com/api/mcp            # Authorization: Bearer rsd_live_…
https://research.ounie.com/api/mcp?api_key=rsd_live_…   # header-less clients
https://research.ounie.com/api/sse            # legacy SSE
ToolWhat it doesCost
researchRun a brief and wait for it. Returns the cited brief, or a brief_id to poll if a deep run outlasts the tool call.by depth
get_briefFetch a brief by id: status, claims, sources, quotes, stats.free
list_briefsList your briefs, optionally filtered by status.free
get_credit_balanceSpendable Ounie credits on the shared wallet.free
get_pricingThe depth ladder and what each rung does upstream. No auth.free
whoamiThe authenticated key's owner and key id.free

A tool call that cannot be funded returns insufficient_creditswith the amount needed and a link to buy — it never runs a partial brief.

x402 — keyless, pay per call

For agents with no Ounie account. Pay in USDC on Base; no key, no wallet with us, no signup.

POST https://research.ounie.com/api/x402/research
{ "question": "…", "depth": "standard" }

→ 402 Payment Required   { accepts: [{ scheme, network, payTo, asset, … }] }

# sign the terms, retry with the header
X-Payment: <base64 signed payload>

→ 202 Accepted
{
  "brief_id": "…",
  "poll_url": "https://research.ounie.com/api/x402/research/…",   # FREE
  "eta_seconds": 60,
  "payment": { "tx_hash": "0x…", "paid_atomic_usdc": "420000" }
}
A search runs before the money moves.A brief takes minutes, so it cannot be held open in one response — but an x402 settlement is final on chain with no refund path. So the check that normally happens at the end is pulled forward: one real search runs before settlement, and a question with no readable sources gets a 400 no_sources_found with your funds untouched.
DepthPriceWhat runs
Quick$0.181 search · up to 6 sources
Standard$0.423 searches · up to 14 sources
Deep$0.906 searches · up to 24 sources

Keyless briefs belong to no account and are reachable only by the id returned at purchase. Polling one is free and never charges twice.

The brief

sources[].index is 1-based and every index appearing in keyFindings[].sources or answer[].sources resolves to one of them. That invariant is enforced before delivery, not asserted here.

{
  "status": "succeeded",              // queued|running|succeeded|thin|failed|aborted
  "credits_spent": 35,
  "confidence": 0.78,
  "brief": {
    "question": "…",
    "depth": "standard",
    "keyFindings": [ { "text": "…", "sources": [1, 3] } ],
    "answer":      [ { "text": "…", "sources": [2] } ],
    "sources": [{
      "index": 1,
      "title": "…",
      "url": "https://…",
      "publishedAt": "2026-07-02T00:00:00.000Z",   // null when unknown — never guessed
      "quote": "the sentence the claim rests on",
      "domain": "example.com"
    }],
    "openQuestions": ["…"],
    "stats": {
      "queriesRun": 3,
      "sourcesConsulted": 14,      // pages fetched and read
      "sourcesCited": 9,           // pages something actually cited
      "claimsDropped": 2,          // claims that cited nothing real
      "citationsRepaired": 1       // indices pointing at no fetched source
    }
  },
  "markdown": "# …"                  // omitted when format="json"
}

A source nobody cited is counted in sourcesConsulted but not shipped in sources— it consumed budget, not trust. Surviving sources are renumbered compactly, so there are never gaps in the indices you are asked to check.

Pricing

DepthCreditsSearchesPages requestedRead / source
Quick15161,200
Standard353243,000
Deep7561206,000

A credit is one cent, drawn from the shared Ounie wallet. Reserved at submit, settled when the brief lands, refunded in full when it is thin, aborted or failed. Reads, exports and polls are free. Manage your wallet.

Errors

StatusMeaning
400The question or a filter was rejected. The message names the field and the fix.
401No session cookie and no valid bearer key.
402insufficient_credits — includes required_credits, balance_credits and buy_credits_url. Nothing upstream ran.
404No such brief for this owner.
429More than 5 briefs already running.
503Search or synthesis is unavailable on this deployment. Nothing was charged.

A finished brief can still carry status: "thin": the run completed and found nothing traceable. That is deliberately distinct from failed, and both refund in full.