Search
Consumer-facing guide to POST /search — the fast lane: one blocking call that returns data now, no agent run. It is the low-latency counterpart to Chat. Where Chat opens a conversation and runs a multi-step Master agent turn server-side (always async, handles only), Search blocks for a single answer: it turns your ask into SQL over your interactions warehouse and runs it, and in blended mode adds a quick web + news citation pass.
Search or Chat?
Reach for Search (POST /search) when… | Reach for Chat (POST /chat) when… |
|---|---|
| You want rows / a count back in one call, right now. | The question needs several steps, judgement, or a written narrative. |
| The ask is a single question over your interaction data. | The ask spans surfaces, needs delegation, or long-form synthesis. |
| A few web + news citations alongside the data is enough. | You want the full market fan-out + the internal-vs-market divergence map. |
| You are wiring a dashboard cell, a slash command, an autocomplete. | You are running an investigation Amdahl should carry out end to end. |
Search settles in seconds (a ~15s hard ceiling). Chat can take minutes. If an ask is too open-ended for the fast lane, Search says so — the response carries escalate_to_chat: true and a plain-language message.
Call it
curl -X POST https://api.amdahl.com/api/platform/v1/search \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "objection-tagged calls in the last 30 days",
"mode": "internal"
}'Parameters
| Field | Default | What it does |
|---|---|---|
query | (required) | The ask, in plain language. |
mode | internal | internal = warehouse only. blended = also fan out web + news for citations. |
limit | 50 | Internal row cap. Max 1000. |
external_limit | 10 | Blended citation cap. Max 24 — the fast lane returns a handful of high-signal citations, not a research corpus. |
synthesize | false | Opt into a one-paragraph headline over the merged evidence. Off by default: the fast lane returns data, not prose, unless asked. |
Unknown fields are stripped; a bad mode / limit surfaces as one invalid_argument error rather than a silent clamp gone wrong.
internal vs blended
internal(default) writes SQL over yourinteractionswarehouse and runs it through the same query gate the rest of the platform uses — your tenant scope, your data-access policy, the truncation guard, and the 1-hour query cache all apply, and one self-repair round re-writes the SQL if the first attempt fails.blendeddoes everythinginternaldoes and fans out a quickweb+newscitation pass under a tight deadline. There is deliberately no rerank and no fusion here — that heavier market synthesis (and the divergence map) is Chat / theexternal_searchtool. Blended needs theexternal_search:executescope; without it the call quietly degrades to internal-only and setsexternal_omitted: "missing_scope"— it never fails for the missing scope.
The result shape
Search never hands back a raw error or stack. Past parameter validation it always returns success: true; every failure mode is a typed field on the result, and a partial answer always beats a 500.
{
"success": true,
"query": "objection-tagged calls in the last 30 days",
"mode": "blended",
"internal": {
"status": "ok",
"sql": "SELECT objection, COUNT(*) AS n FROM interactions WHERE …",
"explanation": "Counts objection-tagged interactions in the last 30 days.",
"rows": [{ "objection": "pricing", "n": 42 }],
"row_count": 1,
"truncated": false,
"cached": false,
"repaired": false,
"note": null
},
"external": {
"citations": [
{ "title": "…", "url": "https://…", "snippet": "…", "source": "web" }
],
"sources_timed_out": []
},
"external_omitted": null,
"synthesis": null,
"message": "Found 1 result over your interactions.",
"escalate_to_chat": false
}Reading it
internal.statusis the warehouse leg's outcome:ok— SQL ran and returned rows (ininternal.rows).empty— SQL ran, zero rows matched. The ask is answerable; nothing fit.internal.noteexplains, andinternal.sqlshows what ran.unsupported— the ask does not fit a single SELECT over the interactions surface, so no SQL was written.escalate_to_chatistrue.failed— SQL was written but execution failed after one self-repair round (or the phase ran out of time).internal.noteis a plain-language explanation — never the raw database error.
internal.sqlis the SQL that ran (or the last attempt). Re-run it yourself viadata.queryfor live numbers, or showinternal.rowsas the snapshot.internal.truncatedistruewhen the row set was capped atlimit;cachedistruewhen the 1-hour cache served it;repairedistruewhen the self-repair round rewrote the SQL.externalis present only on theblendedpath when the external leg ran (nullotherwise). Any source that missed its deadline is listed by id inexternal.sources_timed_out— a slow source loses a citation, never the whole call.external_omittedis"missing_scope"when you asked forblendedbut lackexternal_search:execute;nullotherwise.synthesisis the opt-in one-paragraph headline (only when you passedsynthesize: trueand it succeeded;nullotherwise).escalate_to_chatistruewhen the ask is out of the fast lane's reach and Chat is the better door.
The only success: false shape is a parameter-validation failure:
{ "success": false, "error": { "code": "invalid_argument", "message": "Invalid search request: …" } }Over MCP
The same fast lane is the search tool on the Amdahl MCP server — one action, run, with the same parameters:
{ "action": "run", "query": "top objections this quarter", "mode": "blended" }Use search when you want data back in one call; use the agents tool's Chat actions (start_chat / chat_status / respond / cancel_chat) when you want Amdahl to run a multi-step investigation server-side. The result is data only — no directive text.
Scopes
data:read is all internal needs, so a read-only key can call it. The blended leg additionally checks external_search:execute and degrades to internal-only when it is absent. Both scopes are on the customer-agent key bundle.