Quickstart
This guide takes you from zero to a streaming AI response in three steps. By the end, you will have authenticated, created an AI session, sent a message, and received a streamed reply.
You need a confirmed account with AI access, a person-scoped developer token, curl, and jq. Create the developer token in Developer Access. The exchange below returns a short-lived access token for the session routes.
Environment Variables
Set these before running any example on this page:
export BASE_URL="https://api.chainabit.com/api/v1"
export DEVELOPER_TOKEN="YOUR_DEVELOPER_TOKEN"
export TOKEN="$(curl --fail-with-body -sS -X POST "$BASE_URL/auth/developer-tokens/exchange" \
-H "Content-Type: application/json" \
-d "{\"token\":\"$DEVELOPER_TOKEN\"}" | jq -er '.data.tokens.accessToken')"Developer tokens with an organization-only scope cannot be exchanged for a person-scoped session. You can also use an access token from an existing login; see Authentication.
Step 1: Create an AI Session
A session is a persistent conversation thread. Create one with a title to identify it.
SESSION_RESPONSE="$(curl --fail-with-body -sS -X POST "$BASE_URL/ai/sessions" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"title": "My First Session"}')"
printf '%s\n' "$SESSION_RESPONSE" | jq .
export SESSION_ID="$(printf '%s\n' "$SESSION_RESPONSE" | jq -er '.data.id')"const response = await fetch(`${BASE_URL}/ai/sessions`, {
method: 'POST',
headers: {
Authorization: `Bearer ${TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ title: 'My First Session' }),
});
const { data } = await response.json();
const SESSION_ID = data.id;import requests
response = requests.post(
f"{BASE_URL}/ai/sessions",
json={"title": "My First Session"},
headers={"Authorization": f"Bearer {TOKEN}"},
)
data = response.json()["data"]
SESSION_ID = data["id"]Response 201 Created
{
"data": {
"id": "<session-uuid>",
"title": "My First Session",
"titleGenerationState": "resolved",
"status": "active",
"sessionType": "chat",
"mode": "auto",
"visibility": "private",
"startedAt": "<ISO-8601 timestamp>",
"lastActivityAt": "<ISO-8601 timestamp>",
"archivedAt": null,
"pinnedAt": null,
"chainyId": null,
"metadata": { "title": "My First Session" },
"privacyMode": "standard",
"temporary": false,
"temporaryExpiresAt": null,
"temporaryRetentionDays": null,
"temporaryContextMode": null
}
}The cURL command exports the returned data.id as SESSION_ID for the next step.
Step 2: Send a Message
Send a message into the session. The API accepts plain text content.
curl -X POST "$BASE_URL/ai/sessions/$SESSION_ID/messages" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"content": "What can I build with the Chainabit API?"}'const response = await fetch(
`${BASE_URL}/ai/sessions/${SESSION_ID}/messages`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ content: 'What can I build with the Chainabit API?' }),
}
);
const { data } = await response.json();
const MESSAGE_ID = data.assistantMessage.id;import requests
response = requests.post(
f"{BASE_URL}/ai/sessions/{SESSION_ID}/messages",
json={"content": "What can I build with the Chainabit API?"},
headers={"Authorization": f"Bearer {TOKEN}"},
)
data = response.json()["data"]
MESSAGE_ID = data["assistantMessage"]["id"]Response 201 Created
{
"data": {
"sessionId": "sess_01HQ3K5N2P4R7T9V1X3Z5A7C9E",
"userMessage": {
"id": "msg_01HQ3K7R2S5T8V2Y4A6C8E1G3I",
"role": "user",
"content": "What can I build with the Chainabit API?",
"createdAt": "2026-05-04T10:00:05.000Z"
},
"assistantMessage": {
"id": "msg_01HQ3K8S3T6U9W3Z5B7D0F2H4J",
"role": "assistant",
"content": "",
"status": "pending",
"createdAt": "2026-05-04T10:00:05.100Z"
},
"run": { "id": "run_01HQ3K9T4U7V0X4A6C8E1G3I5K", "status": "queued" },
"effortDowngrade": null
}
}The endpoint creates and returns both messages plus the run that will produce the reply — you stream the assistant message's ID in the next step, not the user message's:
export MESSAGE_ID="msg_01HQ3K8S3T6U9W3Z5B7D0F2H4J"Step 3: Stream the Response
Open a server-sent event (SSE) stream to receive the AI reply in real time.
curl "$BASE_URL/ai/sessions/$SESSION_ID/messages/$MESSAGE_ID/stream" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: text/event-stream"import requests
with requests.get(
f"{BASE_URL}/ai/sessions/{SESSION_ID}/messages/{MESSAGE_ID}/stream",
headers={"Authorization": f"Bearer {TOKEN}", "Accept": "text/event-stream"},
stream=True,
) as r:
for line in r.iter_lines():
if line:
print(line.decode())SSE Output
Native browser EventSource cannot set the required Authorization header. Use a streaming HTTP client that supports request headers.
The first frame on every stream is a connection preamble; each event after that carries a numbered envelope with a payload field specific to its type:
event: stream.connected
data: {"runId": "run_01HQU..."}
id: 1
event: message.delta
data: {"eventId":1,"type":"message.delta","runId":"run_01HQU...","timestamp":"2026-05-04T10:00:06.000Z","payload":{"delta":"You can build"},"v":1}
id: 2
event: message.delta
data: {"eventId":2,"type":"message.delta","runId":"run_01HQU...","timestamp":"2026-05-04T10:00:06.100Z","payload":{"delta":" AI-agent workflows,"},"v":1}
id: 3
event: message.completed
data: {"eventId":3,"type":"message.completed","runId":"run_01HQU...","timestamp":"2026-05-04T10:00:07.000Z","payload":{"runId":"run_01HQU...","messageId":"msg_01HQ3K7R2S5T8V2Y4A6C8E1G3I","content":"You can build AI-agent workflows, integrate connectors, and automate pipelines."},"v":1}Collect message.delta events' payload.delta to assemble the full response. Close the stream on message.completed, which carries the complete payload.content if you'd rather use that directly instead of concatenating deltas.
What's Next
- Get an API key with the right scopes in Developer Access.
- Understand JWT session auth in Authentication.
- Walk through a full AI session tutorial in Run Your First AI Session.
- Browse the complete AI API Reference for all session, message, and streaming endpoints.