Cereal docs
Quickstarts

HTTP quickstart

Create an agent, start a session, and stream its response with curl.

This path uses hosted Cereal directly. You need curl, jq, a Cereal key with read, data, and control, and a key for your existing model provider. Create the Cereal key in Settings → API keys in your development environment.

Export CEREAL_API_KEY and MODEL_API_KEY in your terminal. Set RESEARCH_MODEL to a model enabled for your provider account. Set MODEL_PROVIDER_TYPE to anthropic, openai, openai-compatible, or vercel-ai-gateway. The defaults use Anthropic. For an OpenAI-compatible provider, set MODEL_BASE_URL to that provider's HTTPS endpoint. The Cereal key is bound to exactly one environment. No environment header is needed. Credentials explains keys and permissions.

Run the complete example

Copy this into quickstart.sh, then run bash quickstart.sh. It checks HTTP failures, captures returned IDs, and quotes credentials as JSON. It never requires a TypeScript SDK.

http-quickstart.sh
set -euo pipefail
# Requires curl and jq. Export these credentials before running the script.
: "${CEREAL_API_KEY:?Set a Cereal key with read,data,control}"
: "${MODEL_API_KEY:?Set your model provider key}"
RESEARCH_MODEL=${RESEARCH_MODEL:-claude-sonnet-4.6}
MODEL_PROVIDER_TYPE=${MODEL_PROVIDER_TYPE:-anthropic}
MODEL_BASE_URL=${MODEL_BASE_URL:-}
case "$MODEL_PROVIDER_TYPE" in
  anthropic|openai|vercel-ai-gateway) ;;
  openai-compatible) : "${MODEL_BASE_URL:?Set your model provider endpoint}" ;;
  *) printf 'Unsupported MODEL_PROVIDER_TYPE: %s\n' "$MODEL_PROVIDER_TYPE" >&2; exit 1 ;;
esac

rpc() {
  curl --fail-with-body --silent --show-error \
    "https://app.trycereal.ai/v1/$1" \
    -H "Authorization: Bearer $CEREAL_API_KEY" \
    -H 'Content-Type: application/json' --data-binary @-
}

# 1. Register a provider. jq quotes the secret safely as JSON.
jq -n --arg secret "$MODEL_API_KEY" --arg type "$MODEL_PROVIDER_TYPE" \
  --arg baseUrl "$MODEL_BASE_URL" \
  '{slug:"primary", name:"Primary", type:$type, secret:$secret} +
   (if $baseUrl == "" then {} else {baseUrl:$baseUrl} end)'  \
  | rpc providers/upsert > /dev/null
printf '%s' '{"name":"primary"}' | rpc providers/test | jq .

# 2. Register an agent that needs no tools or application data.
AGENT_ID=$(jq -n --arg model "$RESEARCH_MODEL" \
  '{slug:"hello-http", definition:{name:"Hello HTTP", model:{provider:"primary",model:$model}, system:"Answer general questions concisely.", tools:[], policies:{}, limits:{}}}' \
  | rpc agents/upsert | jq -er '.agentId')

# 3. Start a session. Capture the real ID returned by Cereal.
SESSION_ID=$(jq -n --arg agentId "$AGENT_ID" \
  '{agentId:$agentId, initialMessage:"What is 2 plus 2?"}' \
  | rpc sessions/create | jq -er '.id')
printf 'Session: %s\n' "$SESSION_ID"

# 4. Read the events recorded so far. A turn may still be running.
jq -n --arg id "$SESSION_ID" '{id:$id, after:0}' | rpc sessions/events | jq .

# 5. Mint a read-only token and tail the session from the beginning.
STREAM_TOKEN=$(jq -n --arg id "$SESSION_ID" '{id:$id, format:"cereal", ttlSeconds:300}' \
  | rpc sessions/streamToken | jq -er '.token')
curl --fail-with-body --no-buffer \
  "https://app.trycereal.ai/sessions/$SESSION_ID/stream?format=cereal&after=0" \
  -H "Authorization: Bearer $STREAM_TOKEN"
# Press Ctrl+C after the agent.message and session.status idle events.

The same script is included in the repository.

Expect an agent.message answering four, followed by a session.status whose status is idle and stopReason is completed. The exact wording varies. The SSE connection stays open for future turns; press Ctrl+C after the result. Use the printed session ID to find the trace in the console.

What each operation does

OperationResult
providers.upsertRegisters the named model provider and its credential
agents.upsertRegisters the definition; returns an agent ID and version
sessions.createStarts a session pinned to that definition
sessions.eventsReads the durable events recorded so far
sessions.streamTokenIssues a short-lived credential for one session's stream

All /v1 operations are POSTs with JSON inputs. The stream is a separate GET route using the stream token, not your API key. See HTTP conventions.

Send another message

In another terminal, set CEREAL_API_KEY and SESSION_ID to the values from your first run. Send a follow-up while the original stream is open:

jq -n --arg id "$SESSION_ID" '{id:$id,message:"And 3 plus 3?"}' |
  curl --fail-with-body --silent --show-error \
    https://app.trycereal.ai/v1/sessions/send \
    -H "Authorization: Bearer $CEREAL_API_KEY" \
    -H 'Content-Type: application/json' --data-binary @-

For retried application writes, use a stable idempotencyKey for the same logical create or send. See delivery modes.

Continue without TypeScript

Connect an existing MCP server by registering its URL and naming the connection in the agent's tools. Your application can also mint browser stream tokens using this same HTTP operation. Authorize the customer before returning a token; see streaming integration and streaming protocol.

Understand the configuration

See the agent definition for a field-by-field explanation and the equivalent TypeScript form. Cereal handles the session runtime; this script needs no application server because the example has no custom tools.

On this page