Developers
Calls API
Put a person’s question on the record from your own product. Each expert answers before seeing what the person thinks or what the others said, says how sure they are and what would change their mind, and names the day you will know. When it is settled, the person says how it went and every answer is scored.
Authentication#
Every request carries a Bearer key (sb_live_…) made at /mcp/console, or an OAuth token. Starting and reporting need the session:write scope; reading needs session:read. Open the console.
The flow#
- Ask her. Send the person’s situation to their Chief of Staff with the MCP tool synthboard.ask (one JSON-RPC POST to /api/mcp with the same key). She answers, or returns a card that sizes it — one expert or a board — with the card’s number and a next_action naming synthboard.call.start.
- Show the card and get the person’s yes. Nothing spends without it.
- Start it: POST /api/v1/calls with the card_id. One start per card; a repeat returns the same call.
- Read it: GET /api/v1/calls/{id}?wait_seconds=40 until status is done. The answers stay sealed until every expert has answered.
- Report it: when the person tells you what they did, or how it went, POST /api/v1/calls/{id}. The report waits for the person to confirm it on SynthBoard; only then does the record move.
curl https://www.synthboard.ai/api/mcp \
-H "Authorization: Bearer sb_live_…" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"synthboard.ask","arguments":{"message":"Should we raise our price from $29 to $39 a month?"}}}'
# The reply may arrive as a server-sent event: the JSON is on its data: line.
# Its card (next_actions → synthboard.call.start) carries the card_id.curl -X POST https://www.synthboard.ai/api/v1/calls \
-H "Authorization: Bearer sb_live_…" \
-H "Content-Type: application/json" \
-d '{"card_id":"5b0c2f8e-1d4a-4e8b-9a61-2f3c7d9e4a10"}'curl "https://www.synthboard.ai/api/v1/calls/9d2e41c7-6b3f-4a58-8c1e-0f7a2b5d6e93?wait_seconds=40" \
-H "Authorization: Bearer sb_live_…"curl -X POST https://www.synthboard.ai/api/v1/calls/9d2e41c7-6b3f-4a58-8c1e-0f7a2b5d6e93 \
-H "Authorization: Bearer sb_live_…" \
-H "Content-Type: application/json" \
-d '{"stage":"outcome","outcome":{"result":"well"},"idempotency_key":"outcome-9d2e41c7"}'Endpoints#
| Method | Path | What it does |
|---|---|---|
| POST | /api/v1/calls | Put a call on the record from her card (the person's yes; one start per card) |
| GET | /api/v1/calls | List the person's calls on the record (status, paged) |
| GET | /api/v1/calls/{id} | A call: each expert's take, the chair, the dates, the decision and the outcome |
| POST | /api/v1/calls/{id} | Report a decision or an outcome (pending until the person confirms) |
POST /api/v1/calls
| Field | Type | What it is |
|---|---|---|
| card_id | uuid | The card from synthboard.ask whose next_action names synthboard.call.start. |
| gut | object, optional | A decision only, and only if the person said it before any answer: {choice: take | pass | unsure | other, p?: 0..1, text?}. |
| idempotency_key | string, optional | Accepted for symmetry; the card already starts once. |
POST /api/v1/calls/{id}
| Field | Type | What it is |
|---|---|---|
| stage | decision | outcome | What the person is telling you. |
| decision | object | {choice: followed | didnt | still_open | other, followed_take_id?, text?} — with stage decision. |
| outcome | object | {result: well | badly | mixed | cant_tell, text?} — with stage outcome. |
| idempotency_key | string, optional | The same key returns the same report for a day. |
GET /api/v1/calls
| Query | Type | What it is |
|---|---|---|
| status | open | decided | resolved | on | all | Default on (open, decided and resolved). |
| before | timestamp, optional | The page before this created_at (next_before from the last page). |
| limit | 1–50 | Default 20. |
curl "https://www.synthboard.ai/api/v1/calls?status=open&limit=20" \
-H "Authorization: Bearer sb_live_…"The envelope#
Every call endpoint answers with the same envelope the MCP tools return: what to tell the person (message), the lead answer (take), what to do next (next_actions, each with the tool and arguments to run), and the call block with every expert’s answer. No trace, correlation or account ids leave it — only the call id, the room id and their links.
{
"status": "done",
"ref": {
"kind": "call",
"id": "9d2e41c7-6b3f-4a58-8c1e-0f7a2b5d6e93",
"url": "https://synthboard.ai/session/3f6a9b21-7c4d-4e15-a8b2-c9d0e1f2a3b4"
},
"take": {
"call": "Raise to $39 for new customers now; keep existing customers at $29 for 90 days.",
"why": [
"Churn is low and the price is under the market."
],
"would_change": "If new-customer conversion at $39 drops by more than a fifth in 30 days.",
"confidence": 0.8,
"floor": "If new-customer conversion at $39 drops by more than a fifth in 30 days.",
"resolve_by": "2026-11-20T12:00:00.000Z",
"record": {
"resolved": 3,
"held": 2,
"partly": 1,
"missed": 0
}
},
"objects": [],
"next_actions": [
{
"id": "decide:9d2e41c7-6b3f-4a58-8c1e-0f7a2b5d6e93",
"kind": "resolve",
"label": "When the person tells you what they did, report it (flagged until they confirm)",
"tool": "synthboard.call.resolve",
"args": {
"call_id": "9d2e41c7-6b3f-4a58-8c1e-0f7a2b5d6e93",
"stage": "decision",
"decision": {
"choice": "followed",
"followed_take_id": "a1c3e5f7-0b2d-4f6a-8c9e-1a3b5c7d9e0f"
}
},
"due": "2026-10-23T12:00:00.000Z"
},
{
"id": "do:a1c3e5f7-0b2d-4f6a-8c9e-1a3b5c7d9e0f",
"kind": "start",
"label": "Have The CFO do the move: \"Raise to $39 for new customers now; keep existing customers at $29 for 90 days.\" — about 130 credits, billed at actual cost (the person said yes)",
"tool": "synthboard.job.start",
"args": {
"title": "Raise to $39 for new customers now; keep existing customers at $29 for 90 days.",
"brief": "The CFO's answer on \"Should we raise our price from $29 to $39 a month?\": Raise to $39 for new customers now; keep existing customers at $29 for 90 days. What would change their mind: If new-customer conversion at $39 drops by more than a fifth in 30 days. The person wants the move done: lay out the first steps with dates, and draft anything that has to be written or sent. Keep to the answer; if something on file contradicts it, say so first.",
"lead_expert": "6255b274-75e8-456c-884b-db200bc15fbb",
"gets": [
{
"kind": "plan",
"noun": "plan",
"count": 1
},
{
"kind": "drafts",
"noun": "drafts",
"count": null
}
],
"steps": [
"Read the answer and what would change it",
"Lay out the first steps, with dates",
"Draft what has to be written or sent"
],
"language": "en",
"call_id": "9d2e41c7-6b3f-4a58-8c1e-0f7a2b5d6e93",
"idempotency_key": "do-this-a1c3e5f7-0b2d-4f6a-8c9e-1a3b5c7d9e0f"
},
"due": null
},
{
"id": "record:6255b274-75e8-456c-884b-db200bc15fbb",
"kind": "record",
"label": "The CFO's record with this person",
"tool": "synthboard.record",
"args": {
"synth_id": "6255b274-75e8-456c-884b-db200bc15fbb"
},
"due": null
},
{
"id": "record:47bdcabc-89fa-4475-adfc-19be5e9be94c",
"kind": "record",
"label": "The Skeptic's record with this person",
"tool": "synthboard.record",
"args": {
"synth_id": "47bdcabc-89fa-4475-adfc-19be5e9be94c"
},
"due": null
},
{
"id": "open:9d2e41c7-6b3f-4a58-8c1e-0f7a2b5d6e93",
"kind": "open",
"label": "Open the room on SynthBoard",
"tool": null,
"args": null,
"due": null
}
],
"cost": {
"estimate": null,
"charged": null
},
"check_back_seconds": null,
"message": "On the record: 2 answers. Show the person each expert's answer, how sure, and what would change their mind — as they are. When they decide, report it with synthboard.call.resolve.",
"call": {
"id": "9d2e41c7-6b3f-4a58-8c1e-0f7a2b5d6e93",
"question": "Should we raise our price from $29 to $39 a month?",
"shape": "decision",
"domain": "money",
"room": {
"kind": "board",
"id": "3f6a9b21-7c4d-4e15-a8b2-c9d0e1f2a3b4",
"url": "https://synthboard.ai/session/3f6a9b21-7c4d-4e15-a8b2-c9d0e1f2a3b4"
},
"status": "open",
"decide_by": "2026-10-23T12:00:00.000Z",
"resolve_by": "2026-11-20T12:00:00.000Z",
"created_at": "2026-10-18T08:52:00.000Z",
"takes": [
{
"take_id": "a1c3e5f7-0b2d-4f6a-8c9e-1a3b5c7d9e0f",
"synth_id": "6255b274-75e8-456c-884b-db200bc15fbb",
"expert": "The CFO",
"position_kind": "decision",
"call": "Raise to $39 for new customers now; keep existing customers at $29 for 90 days.",
"stance": "for",
"confidence": 0.8,
"floor": "If new-customer conversion at $39 drops by more than a fifth in 30 days.",
"check_back": {
"days": 30,
"what": "New-customer conversion at $39 against the last 30 days at $29."
},
"resolve_by": "2026-11-20T12:00:00.000Z",
"far_seat": false,
"dissent": false,
"joined_later": false,
"record_badge": {
"resolved": 3,
"held": 2,
"partly": 1,
"missed": 0
}
},
{
"take_id": "b2d4f6a8-1c3e-4a7b-9d0f-2b4c6d8e0a1b",
"synth_id": "47bdcabc-89fa-4475-adfc-19be5e9be94c",
"expert": "The Skeptic",
"position_kind": "decision",
"call": "Don’t raise the whole base yet; run a 20-customer test first.",
"stance": "against",
"confidence": 0.7,
"floor": "If the test cohort keeps more than 95% of its revenue after 60 days.",
"check_back": {
"days": 60,
"what": "Revenue kept by the test cohort."
},
"resolve_by": "2026-11-20T12:00:00.000Z",
"far_seat": false,
"dissent": false,
"joined_later": false,
"record_badge": null
}
],
"waiting_on": [],
"chair": {
"agree": [
"Both want the price change tested on new customers before existing ones."
],
"split": [
{
"who": [
"The CFO",
"The Skeptic"
],
"on": "Whether to raise now or after a 20-customer test."
}
],
"line": "They agree on testing first; they split on timing."
},
"flips": [],
"gut": null,
"decision": null,
"outcome": null,
"pending_report": null,
"asked": null
},
"do_this": {
"title": "Raise to $39 for new customers now; keep existing customers at $29 for 90 days.",
"expert": "The CFO",
"synth_id": "6255b274-75e8-456c-884b-db200bc15fbb",
"take_id": "a1c3e5f7-0b2d-4f6a-8c9e-1a3b5c7d9e0f",
"tool": "synthboard.job.start",
"args": {
"title": "Raise to $39 for new customers now; keep existing customers at $29 for 90 days.",
"brief": "The CFO's answer on \"Should we raise our price from $29 to $39 a month?\": Raise to $39 for new customers now; keep existing customers at $29 for 90 days. What would change their mind: If new-customer conversion at $39 drops by more than a fifth in 30 days. The person wants the move done: lay out the first steps with dates, and draft anything that has to be written or sent. Keep to the answer; if something on file contradicts it, say so first.",
"lead_expert": "6255b274-75e8-456c-884b-db200bc15fbb",
"gets": [
{
"kind": "plan",
"noun": "plan",
"count": 1
},
{
"kind": "drafts",
"noun": "drafts",
"count": null
}
],
"steps": [
"Read the answer and what would change it",
"Lay out the first steps, with dates",
"Draft what has to be written or sent"
],
"language": "en",
"call_id": "9d2e41c7-6b3f-4a58-8c1e-0f7a2b5d6e93",
"idempotency_key": "do-this-a1c3e5f7-0b2d-4f6a-8c9e-1a3b5c7d9e0f"
},
"estimate": 130
},
"disclosure": "The experts are AI — named roles, not people."
}| Field | What it is |
|---|---|
| status | running while the experts answer, done once the answers are in, needs_input when an expert asked first, failed for a void call. |
| ref | The call: kind "call", its id, and the room’s link on SynthBoard. |
| take | The lead answer in one line, with why, what would change it and how sure. |
| objects | Always empty for a call (jobs fill it). |
| next_actions | What to do next, in order: each with a label to say, the tool and the arguments to run it, and a due date when there is one. |
| cost | estimate is the card’s number on a start; charged stays null (the room bills at actual cost). |
| check_back_seconds | While running, when to read again. |
| message | One line to tell the person, or to act on. |
| call | The call block (below). |
| do_this | The next move as one job: an expert does it end to end after the person’s yes. Null while it runs, or when there is nothing to do. |
| card | The sealed answers as a card a host can render (MCP Apps). Set by the server read. |
| disclosure | The one line to show the first time you relay an expert: the experts are AI. |
call
| Field | What it is |
|---|---|
| id | The call id. |
| question | The question as it was put on the record. |
| shape | decision, plan, build, draft, question, work or other. |
| domain | money, people, product, career, family, legal, health, study or other. |
| room | consult (one expert) or board (several), with the room’s id and link. |
| status | open, decided, resolved, lapsed or void. |
| decide_by | When the person said they would decide. |
| resolve_by | When we will know how it went. |
| created_at | When it went on the record. |
| takes | Each expert’s first answer (below). |
| waiting_on | Experts still answering, by name. |
| chair | Where they agree, where they split, and one line on both. |
| flips | Who changed their mind after reading the others, from what to what, and whether new evidence moved them. |
| gut | The person’s own first answer, when they gave one. |
| decision | What the person did, once reported. |
| outcome | How it went, once reported. |
| pending_report | A report waiting for the person to confirm it. |
| asked | An expert’s question before answering; reply with synthboard.consult.message. |
call.takes[]
| Field | What it is |
|---|---|
| take_id | The answer’s id (a decision report can name it as followed_take_id). |
| synth_id | The expert’s id. |
| expert | The expert’s name. |
| position_kind | decision, recommendation, estimate, draft or answer. |
| call | The answer, in one line. |
| stance | A decision only: for, against, conditional or unsure. |
| confidence | How sure, 0 to 1, or null when they would not put a number on it. |
| floor | What would change their mind. |
| check_back | When to look again, and at what. |
| resolve_by | When we will know. |
| far_seat | An outside view: an expert from outside the field. |
| dissent | Seated because everyone else agreed, to argue the other side. |
| joined_later | Answered after the room had spoken. |
| record_badge | The person’s record with this expert, or null before anything resolved. |
Each answer carries the person’s record with that expert (record_badge: resolved, held, partly, missed), or null before anything resolved. Counts only, never a percentage.
Money#
Starting costs the room it runs, quoted on her card: about 45 credits for one expert, about 95 credits for a board on Free. Each card shows what a room like it typically costs; you pay for what it really used. Each key’s daily credit limit applies. Reading, listing and reporting are free.
Errors#
{
"error": {
"code": "not_found",
"message": "No call with that id on this account.",
"correlation_id": "c0ffee12",
"http_status": 404
}
}| Code | Type | What it is |
|---|---|---|
| unauthorized | 401 | No key, or a key that is not valid. |
| scope_missing | 403 | The key lacks session:read or session:write. |
| not_found | 404 | No card or call with that id on this account. |
| validation_error | 400 | A field is missing or malformed, or the card has nothing to put on the record. |
| invalid_session_state | 400 | The card is already starting, or opened a room that is not on the record. |
| insufficient_credits | 402 | The balance cannot cover the card’s number. |
| failed_precondition | 412 | This is off on SynthBoard right now; run the card’s other next_action. |
| rate_limited | 429 | Too many requests; wait retry_after_s. |
Webhooks#
Subscribe to call.decision_due, call.outcome_due, call.floor_crossed, call.answers_sealed to hear when something happens on a person’s matter. Signing, retries and payloads: Webhooks.
The Ask the board button#
Not ready for the API? Drop in the button. It opens SynthBoard in a new tab with the question already in the composer — /try for someone signed out (free, three experts answering sealed), Home for someone signed in. Nothing is sent until they press send.
<div data-synthboard-ask data-question-from="#question"></div>
<script src="https://www.synthboard.ai/embed/board.js" async></script>| Attribute | Type | What it is |
|---|---|---|
| data-synthboard-ask | — | Marks where the button goes. Elements added later are picked up too. |
| data-question | text | The question to carry (500 characters at most). |
| data-question-from | CSS selector | Read the question from this field when the button is pressed (an input, a textarea, or any element’s text). |
| data-lang | auto · en · he | The label’s language. auto reads the page’s lang. |
| data-variant | filled · outline | filled is the brand action; outline sits beside your own primary button. |
| data-theme | light · dark · auto | auto follows the visitor’s system setting. |
| data-label | text | Your own label (40 characters at most). |
// Or from your own code:
SynthBoard.mount(document.querySelector('#ask'), { question: () => form.question.value, lang: 'he' });
SynthBoard.open('Should we raise our price from $29 to $39?'); // from a click handlerThe question rides in the URL fragment (#q=), which browsers never send to a server, so it stays out of logs. The script makes no network requests, sets no cookies, frames nothing and runs no eval; it works under a strict Content-Security-Policy that allows the script’s origin (or its nonce).