API docs

Debrief

One endpoint files a call. Everything else reads what it produced.

Quickstart

Send either the words or the recording. Everything else is optional.

curl -X POST https://debrief.ounie.com/api/debriefs \
  -H "Authorization: Bearer dbf_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "transcript": "[00:04:12] Dana Reyes: Let'"'"'s move to annual billing...",
    "template": "sales"
  }'

Cost: 10 credits. Because you supplied the transcript, no transcription runs and none is charged. Send audio_url instead and 0.05credits per second of audio is added — reserved against the file's own length, settled on what was actually transcribed.

Want the number before you commit? POST /api/quote runs the same checks and the same arithmetic, for free.

Authentication

Three credentials, and they differ in exactly one way.

dbf_live_…
This app's key

Mint it at /dashboard/api-keys. Files, reads, lists and exports — the whole product. Draws your Ounie credits and can be refused, never overdrawn.

ounie_live_…
The fleet master key

Your ounie.com developer key, once you enable fleet access. Everything above, plus the two things that reach ounie.com: brain context and the write-back.

no key at all
x402

Pay per call in USDC on Base. No account, no brains — pass account background inline as context_text if you want it.

Every REST route accepts the key in an Authorization: Bearer header or as ?api_key=, and the browser session cookie works too. A bad key returns 401 — never a redirect, so an agent gets an answer rather than an HTML login page.

POST /api/debriefs

Files one call. Synchronous — the response carries the finished debrief.

transcript
string, optional

The words. At least 200 characters. Send this OR audio_url, never both — a request carrying both is refused rather than silently preferring one.

audio_url
string, optional

A public http(s) URL to a recording. Up to 120 minutes. Non-public addresses are refused for free, before any quote.

template
"sales" | "interview" | "standup" | "research"

Changes what the filing looks for. Defaults to sales. Every value in this enum is implemented — there is no template listed here that does nothing.

participants
string[], optional

Names of the people on the call, if you know them. This is one of only two ways a real name ever appears in the output; see Participants.

title
string, optional

A label for the call. The model may improve on it; it never invents one from nothing.

brain_ids
uuid[], optional

Ounie brains used as BACKGROUND to frame the filing. Retrieval is free and never adds facts the call did not contain. Requires the master key.

save_to_brain
{ brain_id } , optional

Opt-in write-back, per call. Omit it and nothing is written anywhere. Requires the master key.

Response

{
  "ok": true,
  "debrief_id": "…",
  "credits_spent": 10,
  "transcription_credits": 0,
  "transcribed_seconds": 0,
  "timeline": "parsed",
  "anchored": true,
  "participants": [
    { "key": "dana_reyes", "label": "Dana Reyes", "source": "transcript_label" }
  ],
  "participants_inferred": true,
  "writeback": null,
  "debrief": {
    "title": "…",
    "summary": "…",
    "decisions":   [{ "text": "…", "atMs": 252000, "at": "4:12",  "anchored": true }],
    "commitments": [{ "owner": "dana_reyes", "ownerLabel": "Dana Reyes",
                      "what": "…", "dueHint": "before the board meeting",
                      "atMs": 1085000, "at": "18:05", "anchored": true }],
    "objections":  [], "risks": [], "nextSteps": [],
    "quotes":      [{ "speaker": "dana_reyes", "text": "…", "atMs": 366000,
                      "at": "6:06", "anchored": true }],
    "crmFields":   { "stage": null, "budget": null, "timeline": null,
                     "competitors": [], "useCase": null, "nextStepDate": null },
    "anchoredCount": 7,
    "droppedAnchors": 0
  }
}

droppedAnchors counts citations the model produced that did not correspond to a real moment. They are removed, and the count is surfaced rather than hidden — if you want to check that the guard is doing its job, that is the number to watch.

Reading it back

GET /api/debriefs lists, GET /api/debriefs/{id} reads one in full, and GET /api/debriefs/{id}/export?format=md|json|transcript exports it. All free — you paid to make it, not to look at it.

Anchors

In the rest of the Ounie fleet a claim cites a wiki page. Here the source is a recording, so a citation is a POSITION: every decision, commitment, objection, risk and quote carries atMs, the offset in milliseconds, plus at as a readable timecode.

The response's timeline field tells you where those came from:

"words"
we transcribed it

Word-level timings from the transcriber. Exact.

"parsed"
your transcript was timed

Timestamps read out of the transcript you sent. Exact, because whatever produced that file measured them.

"none"
no time information at all

Every atMs is null and anchored is false. We do not interpolate, and we do not spread items across a duration nobody measured. A fabricated timestamp is worse than an absent one, because someone will click it.

Internally the transcript is split into numbered moments and the model cites a moment id, never a time it composed. An id outside the set is dropped — the same discipline as dropping a citation to a page that was never retrieved.

Participants

A name in the output has exactly two legitimate origins: you passed it in participants, or the transcript was labelled and we parsed the labels out. Both are deterministic and happen before the model runs.

If neither applies, the roster is positional placeholders — speaker_1 — and participants_inferred comes back false. The model is shown only those keys and instructed never to write a person's name anywhere.

On the way back, an owner or a quote speaker is kept only if it resolves to that roster. Anything else becomes null. It is not resolved to the closest match and it does not fall back to speaker_1 — on an unlabelled two-person call that would be a coin flip presented as a fact, and the fact would be a named human committing to something they never said.

Audio alone never yields names. The transcription endpoint returns no speaker labels, so a recording with no participants list always produces placeholders. That is a limit of what can be measured, not a feature we skipped.

Write-back

Passing save_to_brain saves the filed debrief into one of your Ounie brains as a page. It is per request. There is no account setting that enables it, and there is no way to make it the default.

The promote is idempotent on debrief:<id>, so a retry updates the same page rather than creating a second one, and the markdown written is byte-identical to export?format=md.

It is best-effort: a failed promote is reported in the writeback object with a reason, and never turns an otherwise successful debrief into an error. You can also save an existing debrief later, over MCP.

Deleting a debrief here does not reach into the brain. Once a page is in your knowledge base it belongs to it, and silently removing it from a different product would be a surprise rather than a courtesy.

Refusals & refunds

Refusals come in two kinds, and the difference is when they are knowable.

4xx, no price
knowable from the request alone

A missing or ambiguous source, a transcript under the minimum, a media type with no audio in it, a non-public address, a recording over the cap. These are always fatal, so they are refused for free — on the x402 rail, before any quote at all, because making an agent sign a payment authorization for a guaranteed failure is worse than refusing it.

422 / 402 thin_material
knowable only after the work

The source held nothing worth filing. Refunded pool-exact on the credit rail; on x402 the 402 is returned BEFORE settlement, so nothing moves on chain.

402 insufficient_credits
wallet is short

Carries required_credits, balance_credits and a top-up URL. Reserve-before-run means a key is refused, never overdrawn.

503 upstream_unavailable
a supplier is refusing

Carries no price and no payment offer of any kind, so an x402 client cannot read it as a quote. If only transcription is affected, the message says so — a caller with their own transcript is still served.

MCP

Streamable HTTP at https://debrief.ounie.com/api/mcp (legacy SSE at /api/sse). Hosts include Claude, Cursor, ChatGPT and the Ounie AI Team.

Endpoint  https://debrief.ounie.com/api/mcp
Header    Authorization: Bearer dbf_live_…

# For hosts that cannot set headers on an HTTP MCP entry:
https://debrief.ounie.com/api/mcp?api_key=dbf_live_…
file_call
10 credits + transcription

The whole product in one tool.

quote_debrief
free

What will this cost, before committing.

list_debriefs · get_debrief · export_debrief
free

Reads of already-paid work.

save_debrief_to_brain
free · master key

Save an already-filed debrief into a brain. Explicit, idempotent.

get_credit_balance · get_pricing · whoami
free

get_pricing needs no token at all.

x402 — pay per call, no account

POST /api/x402/debrief takes the same body as the account rail, minus the two fields that reach ounie.com. Pass context_text instead of brain_ids if you want account background used for framing.

# 1. Ask. The 402 quotes the exact price for THIS request.
curl -X POST https://debrief.ounie.com/api/x402/debrief \
  -H "Content-Type: application/json" \
  -d '{"transcript": "...", "template": "sales"}'

# 2. Repeat with the signed authorization.
curl -X POST https://debrief.ounie.com/api/x402/debrief \
  -H "X-Payment: <base64 payload>" \
  -H "Content-Type: application/json" \
  -d '{"transcript": "...", "template": "sales"}'

USDC on Base, the exact scheme, and the 402 carries the USDC EIP-712 domain in extra so your wallet does not have to guess it.

Two things worth knowing about this rail. First, the ordering is verify → run → settle: an on-chain settlement is final and there is no refund, so nothing is charged until there is a real debrief to hand back. Second, we settle the amount we quoted, even when the recording turns out shorter than its headers claimed — the exact scheme compares the signed value, so a smaller settlement would simply be refused after the work was done. If you want to pay only for the seconds actually transcribed, use the credit rail, which can refund.

A quote is never issued for work we already know cannot succeed. If a supplier is refusing us, you get a 503 with no payment offer in it rather than a price for a guaranteed failure.

Get a key

Mint a dbf_live_ key on the dashboard, or enable fleet access on ounie.com to use your ounie_live_ master key here.

Open API keys