Send a message and stream the agent's reply.
const url = 'https://shiftagent.example.com/conversations/example/messages?stream=true';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"content":"Summarize today\'s open jobs."}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url 'https://shiftagent.example.com/conversations/example/messages?stream=true' \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "content": "Summarize today'\''s open jobs." }'Appends a user message and runs the agent. Default response is a
streaming application/x-ndjson body (200): the platform’s
native agent event stream, one JSON object per line. Pass
?stream=false for a blocking 201 with the completed assistant
Message JSON instead.
Stream protocol (X-Shiftagent-Stream-Format: claude-sdk/1)
The stream is raw Claude Agent SDK events passed through
verbatim — the adapter translates them into whatever shape its
host system needs. Known top-level type values:
system— run initialization (carries the session id).stream_event— incremental deltas; text arrives astext_deltachunks insidecontent_block_deltaevents.assistant/user— complete turn payloads, including tool calls and tool results.result— the terminal event: run outcome (success or error subtype) plus usage. Exactly one per complete stream.
Interleaved platform lines: {"event":"ping"} keepalives, queued
platform notices under capacity hold, and
{"object":"platform.event","type":"error"} carrying an RFC 9457
problem when the platform (not the agent) aborts the run — e.g.
missing-secret. New event types are additive: ignore unknown
lines. A stream that closes without a terminal line is truncated —
the run continues server-side; reconcile via listMessages (the
assistant message lands in history regardless).
{"object":"platform.event","type":"queued","position":2,"retry_hint_seconds":15}
{"type":"system","subtype":"init","session_id":"…","tools":[…]}
{"type":"stream_event","event":{"type":"content_block_delta","delta":{"type":"text_delta","text":"You have three open jobs"}}}
{"event":"ping"}
{"type":"assistant","message":{"content":[…]}}
{"type":"result","subtype":"success","usage":{…}}
Per-message knobs
skill_ids— narrow to specific skills so the agent context stays lean (must be within the conversation’s effective skills; the repository is always the tenant’s).env— plaintext, non-secret run parameters. Never place secret material here — the runtime sees these values verbatim.secrets— write-onlyalias → valuemap, vaulted on arrival and scoped to this message’s run (ephemeral; resolved before conversation-, user-, and tenant-scoped secrets). Values never appear in any response; the agent sees only{{secret:ALIAS}}placeholders, resolved by the egress proxy at the network boundary.filler {enabled}— override the filler cascade for this message (tenant → conversation → message; filler output is part of the reply, indistinguishable by design).on_capacity—reject(default):429capacity-exhausted+Retry-Afterwhen no sandbox is available;hold: the stream first emitsqueuedplatform notices, bounded by the deployment’s max hold time.
Missing secrets fail fast
A run that references a secret alias vaulted at no scope terminates
with a missing-secret platform error line naming the alias
(?stream=false → 422 problem). Re-send the message with the
secret attached — a one-step retry; there is no mid-run pause.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”Internal conversation ID.
Header Parameters
Section titled “Header Parameters ”Optional idempotency key (any unique string, e.g. a UUID; max 255 chars). Responses are cached 24h per (key principal, operation, key); replays return the original status and body with Idempotency-Replayed: true. Reusing a key with a different payload responds 409 idempotency-key-conflict.
Query Parameters
Section titled “Query Parameters ”true (default) streams the native agent event stream; false blocks until the run completes and returns the assistant message as JSON.
Request Body required
Section titled “Request Body required ”Body for createMessage (and initial_message on createConversation).
object
The user’s message text.
Optional typed blocks (extensibility).
Typed content block — the extensibility seam for richer runs. Known types: text, tool_call, tool_result; unknown types must be ignored by clients.
object
Block type (open enum).
Text content (for text blocks).
Per-message skill narrowing — keeps the agent context lean. Must be within the conversation’s effective skills.
Plaintext, non-secret run parameters, visible to the agent verbatim. Never place secret material here — use secrets.
object
Write-only alias → value map, scoped to this message’s run (ephemeral — resolved before conversation-, user-, and tenant-scoped secrets). Never echoed anywhere; the agent sees only {{secret:ALIAS}} placeholders resolved by the egress proxy.
object
Per-message filler override (most specific wins).
object
Whether the low-latency filler agent runs for this scope.
reject → 429 capacity-exhausted + Retry-After when no sandbox is available; hold → the stream first emits queued platform notices until one frees (bounded by the deployment’s max hold time).
Free-form string key–value map for host/adapter bookkeeping (e.g. a host-side reference ID). Max 50 keys; values max 500 chars. Replaced wholesale when provided in updates.
object
Examples
Plain message
{ "content": "Summarize today's open jobs."}Skill narrowing + env + message-scoped secrets
{ "content": "Reconcile yesterday's invoices against the CRM.", "skill_ids": [ "skl_01hzx8invoice" ], "env": { "REGION": "us-east", "REPORT_DATE": "2026-07-01" }, "secrets": { "CRM_API_KEY": "example-value-vaulted-never-echoed" }, "filler": { "enabled": false }, "on_capacity": "hold"}Responses
Section titled “ Responses ”The native agent event stream (default): raw Claude Agent SDK
events plus platform notice lines, terminated by the agent
result event (or a platform error line). See the operation
description for the full protocol and an end-to-end transcript.
One NDJSON stream line. The stream is the platform’s native agent
event stream — raw Claude Agent SDK events passed through verbatim
(vocabulary versioned by the X-Shiftagent-Stream-Format response
header, currently claude-sdk/1) — interleaved with platform lines:
- Agent events carry a top-level
type—system,stream_event,assistant,user, and the terminalresult. {"event":"ping"}— keepalive.{"object":"platform.event","type":"queued","position":n, "retry_hint_seconds":n}— capacity hold notice.{"object":"platform.event","type":"conversation", "conversation":{…}}— leading line on create/upsert-with-initial_messagestreams, carrying the conversation.{"object":"platform.event","type":"error","problem":{…}}— terminal platform abort carrying an RFC 9457 problem (e.g.missing-secret).
Clients MUST ignore unknown line shapes (new event types are
additive). Exactly one terminal line (result or platform error)
ends every complete stream; a stream that closes without one is
truncated — reconcile via listMessages.
object
Examples
Platform notice: held for capacity (on_capacity=hold)
{ "object": "platform.event", "type": "queued", "position": 2, "retry_hint_seconds": 15}Agent event: run initialization
{ "type": "system", "subtype": "init", "session_id": "3f7c9a12-6c1e-4b8a-9f27-c11d2e83a001"}Agent event: incremental reply text
{ "type": "stream_event", "event": { "type": "content_block_delta", "delta": { "type": "text_delta", "text": "You have three open jobs today." } }}Platform keepalive
{ "event": "ping"}Agent event: terminal result (exactly one per stream)
{ "type": "result", "subtype": "success", "usage": { "input_tokens": 2048, "output_tokens": 96 }}Platform notice: terminal problem-typed error
{ "object": "platform.event", "type": "error", "problem": { "type": "https://shiftagent.example.com/problems/missing-secret", "title": "Missing secret", "status": 422, "detail": "Alias CRM_API_KEY is vaulted at no scope; re-send with the secret attached.", "request_id": "req_01hzx8err001" }}Headers
Section titled “Headers ”Stream vocabulary version (e.g. claude-sdk/1).
Completed assistant message (only with ?stream=false). The user message and this reply both land in history.
A persisted conversation message. Write-only request fields (secrets) are never present; env is echoed as sent (non-secret by contract).
object
Author role.
Full text content. Assistant content references secrets only by alias ({{secret:ALIAS}}) — never by value.
Typed content blocks.
Typed content block — the extensibility seam for richer runs. Known types: text, tool_call, tool_result; unknown types must be ignored by clients.
object
Block type (open enum).
Text content (for text blocks).
Per-message skill narrowing used for this run.
Plaintext run parameters as sent (never secret material by contract).
failed — the run errored or was aborted by the platform (e.g. missing-secret).
Free-form string key–value map for host/adapter bookkeeping (e.g. a host-side reference ID). Max 50 keys; values max 500 chars. Replaced wholesale when provided in updates.
object
RFC 3339 / ISO 8601 timestamp, UTC.
Example
{ "object": "message", "role": "user", "status": "completed"}Missing or invalid credentials — no bearer token, an unknown/revoked sk_int_ key, or an expired platform JWT.
RFC 9457 problem+json error envelope. type is a URI under https://shiftagent.example.com/problems/{slug} (deployment host substituted); see the API-level problem registry for every slug.
object
Problem type URI (registry slug).
Short, human-readable summary of the problem type.
HTTP status code.
Human-readable explanation specific to this occurrence.
URI reference identifying this occurrence.
Correlation ID for support and log lookup.
On name-conflict, external-id-conflict, and resource-in-use: the ID of the existing/depended-on resource — fetch it and continue (replay recovery).
On validation-error, field-level details.
object
JSON pointer to the offending field.
What failed.
Examples
Missing or invalid bearer token
{ "type": "https://shiftagent.example.com/problems/insufficient-scope", "title": "Unauthorized", "status": 401, "detail": "Provide a valid sk_int_ service key or platform JWT.", "request_id": "req_01hzx8auth001"}Forbidden — tenant-suspended (writes to a suspended tenant) or insufficient-scope (key/token lacks the scope or a platform JWT reaches beyond its user).
RFC 9457 problem+json error envelope. type is a URI under https://shiftagent.example.com/problems/{slug} (deployment host substituted); see the API-level problem registry for every slug.
object
Problem type URI (registry slug).
Short, human-readable summary of the problem type.
HTTP status code.
Human-readable explanation specific to this occurrence.
URI reference identifying this occurrence.
Correlation ID for support and log lookup.
On name-conflict, external-id-conflict, and resource-in-use: the ID of the existing/depended-on resource — fetch it and continue (replay recovery).
On validation-error, field-level details.
object
JSON pointer to the offending field.
What failed.
Examples
Suspended tenant rejects conversation writes
{ "type": "https://shiftagent.example.com/problems/tenant-suspended", "title": "Tenant suspended", "status": 403, "detail": "Tenant tnt_01hzx8acme001 is suspended; conversation writes are rejected.", "request_id": "req_01hzx8sus001"}Not found — the resource does not exist, was deprovisioned, or lies outside the integration key’s subtree (indistinguishable by design).
RFC 9457 problem+json error envelope. type is a URI under https://shiftagent.example.com/problems/{slug} (deployment host substituted); see the API-level problem registry for every slug.
object
Problem type URI (registry slug).
Short, human-readable summary of the problem type.
HTTP status code.
Human-readable explanation specific to this occurrence.
URI reference identifying this occurrence.
Correlation ID for support and log lookup.
On name-conflict, external-id-conflict, and resource-in-use: the ID of the existing/depended-on resource — fetch it and continue (replay recovery).
On validation-error, field-level details.
object
JSON pointer to the offending field.
What failed.
Examples
Unknown resource
{ "type": "https://shiftagent.example.com/problems/not-found", "title": "Not found", "status": 404, "detail": "No tenant with external_id acme:tenant:999999.", "request_id": "req_01hzx8nf001"}Conflict — name-conflict / external-id-conflict (unique name or external ID taken; conflicting_resource_id names the holder — fetch it and continue), resource-in-use (guarded delete refused), cross-tenant (referenced resource belongs to another tenant), conversation-archived (write to an archived conversation), or idempotency-key-conflict (same key, different payload).
RFC 9457 problem+json error envelope. type is a URI under https://shiftagent.example.com/problems/{slug} (deployment host substituted); see the API-level problem registry for every slug.
object
Problem type URI (registry slug).
Short, human-readable summary of the problem type.
HTTP status code.
Human-readable explanation specific to this occurrence.
URI reference identifying this occurrence.
Correlation ID for support and log lookup.
On name-conflict, external-id-conflict, and resource-in-use: the ID of the existing/depended-on resource — fetch it and continue (replay recovery).
On validation-error, field-level details.
object
JSON pointer to the offending field.
What failed.
Examples
Named sub-resource already exists — recoverable
{ "type": "https://shiftagent.example.com/problems/name-conflict", "title": "Name conflict", "status": 409, "detail": "A role named \"csr\" already exists in this tenant.", "conflicting_resource_id": "rol_01hzx8csr001", "request_id": "req_01hzx8conf01"}Guarded delete refused
{ "type": "https://shiftagent.example.com/problems/resource-in-use", "title": "Resource in use", "status": 409, "detail": "Repository is attached to 1 tenant and pinned by 2 roles.", "conflicting_resource_id": "tnt_01hzx8acme001", "request_id": "req_01hzx8used01"}Unprocessable — validation-error (schema/semantic validation failed; errors[] lists JSON-pointer details), role-required (the user has no role assigned, so no conversation context can resolve), or missing-secret (a referenced alias is vaulted at no scope).
RFC 9457 problem+json error envelope. type is a URI under https://shiftagent.example.com/problems/{slug} (deployment host substituted); see the API-level problem registry for every slug.
object
Problem type URI (registry slug).
Short, human-readable summary of the problem type.
HTTP status code.
Human-readable explanation specific to this occurrence.
URI reference identifying this occurrence.
Correlation ID for support and log lookup.
On name-conflict, external-id-conflict, and resource-in-use: the ID of the existing/depended-on resource — fetch it and continue (replay recovery).
On validation-error, field-level details.
object
JSON pointer to the offending field.
What failed.
Examples
Field-level validation failure
{ "type": "https://shiftagent.example.com/problems/validation-error", "title": "Validation error", "status": 422, "detail": "One or more fields failed validation.", "errors": [ { "pointer": "/skill_access/skill_ids/0", "message": "skl_01hzx8unknown does not belong to the tenant's repository." } ], "request_id": "req_01hzx8val001"}User has no role at conversation creation
{ "type": "https://shiftagent.example.com/problems/role-required", "title": "Role required", "status": 422, "detail": "User usr_01hzx8jane001 has no role assigned; assign one before starting conversations.", "request_id": "req_01hzx8role01"}Too many requests — capacity-exhausted (no sandbox available, or the maximum hold time elapsed under on_capacity=hold) or rate-limited. Honor Retry-After.
RFC 9457 problem+json error envelope. type is a URI under https://shiftagent.example.com/problems/{slug} (deployment host substituted); see the API-level problem registry for every slug.
object
Problem type URI (registry slug).
Short, human-readable summary of the problem type.
HTTP status code.
Human-readable explanation specific to this occurrence.
URI reference identifying this occurrence.
Correlation ID for support and log lookup.
On name-conflict, external-id-conflict, and resource-in-use: the ID of the existing/depended-on resource — fetch it and continue (replay recovery).
On validation-error, field-level details.
object
JSON pointer to the offending field.
What failed.
Examples
Sandbox pool exhausted (on_capacity=reject)
{ "type": "https://shiftagent.example.com/problems/capacity-exhausted", "title": "Capacity exhausted", "status": 429, "detail": "No sandbox available; retry after the indicated delay or use on_capacity=hold.", "request_id": "req_01hzx8cap001"}Headers
Section titled “Headers ”Seconds to wait before retrying.