Overview
Every call on the public API at a glance: the Message Optimizer, the two primitives (Search and Eval), Research, the orchestration layer built on them, connections, the status codes to handle, and the scopes each one needs.
The public API is the Message Optimizer, which needs no connected data, plus two primitives over your corpus and an orchestration layer on top of them. Primitives explains the model; this page is the at-a-glance table.
- Message Optimizer:
messages.optimize, what you know about the recipient in and one outbound message out, in the sender's voice, on the same call. A draft is optional: sent with context, it is the starting point. A style pass by default; withevidence: "workspace", also graded against your customers' own words. - Search:
search.query, one synchronous call over your warehouse, routed to a typed-filter, NL-to-SQL, meaning-based or exact-term lane; plus thesearch.fieldscatalog and thesearch.overviewdata check. - Eval:
evals.run, an async grade of a prompt and/or a drafted message against verbatim quotes from your own calls and emails, with an improved reusable prompt. The built-in instrument isprompt-and-message-eval. - Research:
research.start, one question in and one cited answer out. A read-only agent investigates it over your calls, accounts and deals; you pollresearch.getfor the answer. - Orchestration: Chat runs a server-side agent over both; the agent library, Routines and Subscriptions store and trigger those runs.
- Connections: the data sources that fill the corpus.
Every call at a glance
| Call | Operation | REST | MCP tool | Scope | Typical latency |
|---|---|---|---|---|---|
| Write a message | messages.optimize | POST /messages/optimize | optimize_message | messages:execute | usually 1-2 min, same call; 300s ceiling |
| Routed search | search.query | POST /search/query | search_customers | data:read | ~2s, 15s ceiling |
| Field catalog | search.fields | GET /search/fields | list_search_fields | data:read | sub-second |
| Data overview | search.overview | GET /search/overview | resource search-overview://current | data:read | one warehouse read per surface |
| Grade content | evals.run | POST /evals/run | run_eval | evals:execute | async, minutes |
| Research a question | research.start | POST /research | start_research | conversations:write | async, minutes |
| Read a research job | research.get | GET /research/:id | get_research | conversations:read | sub-second, or wait_ms |
| Start a Chat | chat.start | POST /chat | start_chat | conversations:write | async |
| Agent library CRUD | agents.*_agent | /agents[...] | list_agents, get_agent, create_agent, update_agent, delete_agent | agents:read / agents:write | sub-second |
| Routines CRUD + fire | routines.* | /routines[...] | list_routines, get_routine, create_routine, update_routine, delete_routine, run_routine_now | routines:read / routines:write | sub-second |
| Connections | connections.* | /connections[...] | list_connections, get_connection, connect_source, reconnect_connection and the rest (Connections) | connections:read / :write | sub-second |
messages.optimize (the Message Optimizer) needs no connected data. By default it is a style pass; send evidence: "workspace" once your conversations are connected and it is also graded against what your own customers said. Calls made with an API key or a connected agent are capped at 1,000 a month per workspace.
External research starts are capped at 100 a month per workspace.
Status codes to handle
Past parameter validation the synchronous calls return success: true with typed fields for degradations (an empty corpus, an unmaterialized index, a failed lane read). That covers degradations, not failures, so there is still a real non-2xx set:
| Status | Codes | What it means |
|---|---|---|
| 400 | invalid_input, invalid_argument | The body failed the schema (details.errors[]), or named a field, operator or id that does not exist. Fix the payload; do not retry. |
| 401 | (string body, no code) | The key is missing, malformed, revoked or expired. |
| 403 | forbidden, not_on_public_api | The key lacks the scope (named in message), or the operation is console-only. Both are terminal for that credential. |
| 429 | rate_limited, quota_exceeded | Back off on the first, honouring Retry-After. The second is an exhausted monthly cap and is terminal until the month rolls. |
| 5xx | operation_error, query_failed, internal_error | The call faulted server-side. Retry with exponential backoff and jitter, and quote the X-Request-Id if it persists. |
POST /search/query also draws on a budget of 10 warehouse reads per minute per user, underneath the global limit of 300 reads per minute per credential. One plain-language search can spend several reads, and on that lane running out comes back as 200 with detail.internal.status: "failed" rather than 429. See Rate limits. Every error shape and code is on Errors.
How the calls chain
Each Search call is one blocking round trip, which makes them composable. The canonical chain is find the cohort, then read what it said:
Structured search
"Closed-won deals this year, largest first": real pipeline company ids.
mode=filter
Semantic search
The objections those accounts already raised, scoped to those ids.
mode=semantic
Two more worth knowing:
- Discovery first:
GET /search/fields, then compose typed filters, thenPOST /search/query. The catalog is derived from the same schema the compiler validates against, so a wrong field name comes back as a typedinvalid_argumentnaming the allowed set. - Grade before you send: whatever wrote the message,
POST /evals/rungrades it against what your buyers said, and you gate on the verdict. It is read-pure, so it is safe in that path. See Gate before send.
When a step needs judgment rather than retrieval, or outside market signal, hand it to Chat. The full set is on Patterns.
Scopes
Create a key with amdahl keys create or in the console (see Authentication) and send it as X-API-Key or Authorization: Bearer.
| Family | Scope |
|---|---|
Write an outbound message (messages.optimize) | messages:execute |
search.query / search.fields / search.overview | data:read |
| Fire an eval, record eval feedback | evals:execute |
| Poll an eval run, browse evals, compare runs | evals:read |
| Author an eval | evals:write |
| Start or rename a Chat | conversations:write |
| Read a Chat, poll a run | conversations:read |
| Answer a pause, cancel a run | workflows:write |
| Agent library read / write | agents:read / agents:write |
| Routines read / write | routines:read / routines:write |
A Read only key can call every Search operation, read Chats, and browse and poll evals. It cannot write a message, start a Chat, fire an eval, answer a pause, or write an agent or routine.
See also
- Message Optimizer, Search and Evals API: the per-call references.
- Tool catalog: every operation with its scopes, generated from the registry.