API reference
This section describes the Syntic API field by field: the base URL, how calls are authenticated, the shape of every request and response, the headers you get back, and every error code. If you are new to the API, the Quickstart gets a first reply on screen faster; come back here when you need exact details.
At a glance
| Item | Value |
|---|---|
| Base URL | https://app.syntic.ai/v1 |
| Protocol | HTTPS only |
| Authentication | Authorization: Bearer <private key> |
| Request format | JSON body, Content-Type: application/json |
| Response format | JSON, or server-sent events when streaming |
| Default response mode | Streamed (stream defaults to true) |
| Endpoints | POST /chat/completions |
| Rate limit | 600 requests per minute per API key |
| Largest request body | About 2 MB, at most 500 messages |
| Machine-readable spec | https://app.syntic.ai/api/openapi (OpenAPI 3.0, YAML) |
Base URL
https://app.syntic.ai/v1Every endpoint path in this reference is appended to that URL. For example, chat completions live at https://app.syntic.ai/v1/chat/completions. Plain http:// is not served.
API host
Planned address change. All examples in these docs use https://app.syntic.ai/v1, which is the address to use today. After the planned switch, https://api.syntic.ai/v1 becomes the official API address. https://app.syntic.ai/v1 keeps working as a permanent alias with the same paths, keys, limits and responses, so existing code does not have to change.
To make the later switch a one-line change, keep the base URL in one place:
export SYNTIC_BASE_URL="https://app.syntic.ai/v1"
curl -sS "$SYNTIC_BASE_URL/chat/completions" \
-H "Authorization: Bearer $SYNTIC_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "Amara Quick", "stream": false, "messages": [{"role": "user", "content": "ping"}]}'Conventions for new endpoints
IDs and timestamps
- Every resource has a string
idwith a short type prefix:agt_agents,sesn_sessions,exec_executions,env_environments,mem_memory stores,vlt_vaults,dep_deployments,file_files,batch_batches,wrkspc_workspaces,user_members,invite_invites,apikey_API keys,whk_webhooks,evt_events. Treat ids as opaque strings up to 64 characters. - Every object has a
typefield naming what it is. - Timestamps are RFC 3339 strings in UTC, such as
2026-11-05T10:00:00Z. - Money is a decimal string in US dollars, such as
"12.3400", to avoid floating-point rounding.
List endpoints
Every GET that returns a list uses the same cursor pagination:
| Query parameter | Default | Notes |
|---|---|---|
limit | 20 | 1 to 100 unless the endpoint says otherwise. |
after_id | Return items after this id (the next page). | |
before_id | Return items before this id (the previous page). |
{
"data": [ { "id": "agt_01JC...", "type": "agent" } ],
"has_more": true,
"first_id": "agt_01JC...",
"last_id": "agt_01JB..."
}To read everything, keep requesting with after_id set to the last last_id until has_more is false. Lists are newest first unless the endpoint says otherwise.
Idempotency
Any POST that creates something accepts an Idempotency-Key header (up to 255 characters). If the same key arrives again within 24 hours with the same body, the original response is returned and nothing new is created. The same key with a different body fails with 409 idempotency_key_reused. Use a fresh UUID per logical operation and reuse it only when retrying that operation.
Updates and deletes
PATCHchanges only the fields you send. Arrays are replaced whole.DELETEreturns{"id": "...", "type": "<object>_deleted"}.
Errors, versions, limits
- Errors use the error envelope.
- Behaviour is pinned with the
syntic-versionheader; preview endpoints also need asyntic-betaflag. See Versioning and beta flags. - Every response carries a request id. Rate-limit headers appear only on a
429.
Endpoints
| Method | Path | What it does |
|---|---|---|
POST | /chat/completions | Generate the next assistant message for a conversation, as one JSON reply or as a stream. |
That is the complete public surface today. There is no endpoint for listing models, embeddings, files, batches or account administration; those tasks happen in the Syntic Console. The models you can name in a request are listed on Models overview.
Authentication
Every request carries a private credential as a bearer token:
Authorization: Bearer sk_live_...Create private keys in the Console under Settings → API Keys. Public pk_live_ keys are refused. Keys can be locked to a list of website origins, and a key only works while its owner is still an active member of the key’s organization. The full rules, including every authentication error, are on Authentication.
Request format
- Send
POSTrequests with a JSON body and the headerContent-Type: application/json. - The raw body may be up to about 2 MB (2,000,000 bytes). Larger bodies are refused with
413 payload_too_large, both when theContent-Lengthheader says so and when the bytes actually received exceed it. - A conversation may hold at most 500 messages. More returns
413 too_many_messages. - Fields the API does not recognise are ignored rather than rejected, so libraries that send extra fields keep working.
Response format
- A request with
"stream": falsegets one JSON object withContent-Type: application/json. - Any other request, including one that leaves
streamout, gets a stream of server-sent events withContent-Type: text/event-stream. The event format is described on Stream format. - Errors are JSON with a short string code in
error. See Error codes.
Streaming is the default. Many client libraries assume the opposite, so set "stream": false explicitly whenever your code expects a single JSON reply.
Response headers
| Header | When it appears | Meaning |
|---|---|---|
x-syntic-request-id | On every response except 405 and 500 | A unique id for this request. Log it and quote it when you contact support. |
x-syntic-billing-source | On successful replies | subscription when the request was covered by your plan’s token allowance, api_credit when it was paid from the usage-credit wallet. |
x-syntic-model-downgraded | When the model you named is not included in your plan | The name of the model that actually answered (the default model). |
Retry-After | On 429, and on 503 | Seconds to wait before the next attempt. Read it before any other header. |
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset-Seconds | Only on a 429 from the request cap | The per-minute cap, the requests left (always 0 on a 429) and seconds until a slot frees up. |
Plans, allowances and the credit wallet are explained in Usage & cost and Billing & credits.
Calling from a browser
The API answers cross-origin requests from any website: preflight OPTIONS requests succeed, and the Authorization and Content-Type headers are allowed. Browsers can read x-syntic-request-id and x-syntic-billing-source from the response. They cannot read x-syntic-model-downgraded or the rate-limit headers, so browser code should not rely on them.
Anyone who loads your page can read a key embedded in it. If a browser must call the API directly, give that page its own key, restrict the key to your site’s origins (see Origin allowlists) and keep its organization’s spend limit low. The safer design is to call the API from your own server.
Rate limits and quotas
Two separate checks can stop a request:
- Rate limit. Each API key may send 600 requests in any rolling 60-second window. Requests signed in with a Syntic Code session are limited per user instead. Going over returns
429with the headers above. - Usage quota. Tokens are drawn first from your plan’s monthly, weekly and 5-hour allowances, then from the usage-credit wallet if your organization has turned credits on. When neither can cover a request you get
402 quota_exhausted, with alimitfield naming the cap that was hit.
The numbers for each plan are on Limits. For a retry and back-off pattern, see Handle usage limits.
What the API adds to your request
Before your conversation reaches the model, the API places a short Syntic identity instruction at the start of the system prompt. If your first message has the system role, your text is kept and follows that instruction; otherwise the instruction is added as a new first message. Your own instructions still apply, but questions such as “which model are you?” will be answered as Syntic AI.
Stability
The API has a single version, reflected in the /v1 path. There is no version header to send. A dated syntic-version header and syntic-beta preview flags are planned; see Versioning and beta flags. Fields may be added to responses over time, so parse JSON leniently and ignore fields you do not know.
Related pages
- Chat completions: the endpoint, every field and full examples
- Authentication: credentials, origin allowlists and auth errors
- Stream format: reading the event stream
- Error codes: every status and code
- OpenAPI description: generate clients and import into tools
- Versioning and beta flags
- Rate-limit headers
- Request IDs