Run Your First AI Session
In this tutorial you will create an AI conversation session, send messages, stream responses in real time using Server-Sent Events (SSE), and execute AI feature runs.
Prerequisites
- A Chainabit account with a valid access token
curlavailable in your terminal- A plan that includes AI credits (check your balance at
/wallet/me)
Set your environment variables:
export TOKEN="your-access-token"Step 1: Check Available AI Providers
Before starting a session, check which AI providers your plan gives you access to:
curl -s "https://api.chainabit.com/api/v1/ai/providers" \
-H "Authorization: Bearer $TOKEN"Response includes an isAccessible flag per provider:
{
"data": [
{
"key": "google",
"displayName": "Google",
"isActive": true,
"isAccessible": true
},
{
"key": "openai",
"displayName": "OpenAI",
"isActive": true,
"isAccessible": true
},
{
"key": "anthropic",
"displayName": "Anthropic",
"isActive": true,
"isAccessible": false
}
]
}isAccessible: true means your plan grants access to that provider. Use a provider key (e.g. openai) when sending messages.
Free plan: only
Step 2: Create a New AI Session
A session holds a conversation thread:
curl -s -X POST "https://api.chainabit.com/api/v1/ai/sessions" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "title": "Fitness coaching" }'Response:
{
"data": {
"id": "session_01HQS...",
"title": "Fitness coaching",
"status": "active",
"startedAt": "2026-03-17T10:00:00.000Z"
}
}Save the session ID:
export SESSION_ID="session_01HQS..."Step 3: Send a Message
Post a message to the session. Optionally pass a provider and effortMode to control which AI is used:
curl -s -X POST "https://api.chainabit.com/api/v1/ai/sessions/$SESSION_ID/messages" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": "I want to build a morning reporting workflow. I have 45 minutes before work. What activities should I include?",
"provider": "openai",
"effortMode": "thinking"
}'| Field | Values | Description |
|---|---|---|
provider | google, openai, anthropic, mistral, and others — see GET /ai/providers for the full, current list | Provider to use. Defaults to google. Every provider other than google requires a paid plan with that provider's entitlement. |
effortMode | basic, thinking, pro | Model tier. basic = fast, thinking = balanced, pro = most capable. |
Both fields are optional — omitting them uses your plan's default (Google, basic).
Response:
{
"data": {
"sessionId": "session_01HQS...",
"userMessage": {
"id": "msg_01HQT...",
"role": "user",
"content": "I want to build a morning reporting workflow. I have 45 minutes before work. What activities should I include?",
"createdAt": "2026-03-17T10:01:00.000Z"
},
"assistantMessage": {
"id": "msg_01HQU...",
"role": "assistant",
"content": "",
"status": "pending",
"createdAt": "2026-03-17T10:01:00.100Z"
},
"run": { "id": "run_01HQU...", "status": "queued" },
"resolvedModel": { "modelKey": "gpt-4o", "displayName": "GPT-4o", "provider": "openai", "reason": "explicit" },
"effortDowngrade": null
}
}The endpoint creates and returns both messages plus the run that will produce the reply. Save the assistant message's ID — that's what you stream in the next step, not the user message's:
export MESSAGE_ID="msg_01HQU..."Step 4: Stream the AI Response via SSE
Connect to the SSE streaming endpoint to receive the AI response in real time. Use curl -N to disable buffering:
curl -N "https://api.chainabit.com/api/v1/ai/sessions/$SESSION_ID/messages/$MESSAGE_ID/stream" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: text/event-stream"SSE Event Format
The server sends events in the standard SSE format. Each event has a type and a JSON data payload:
event: message.delta
data: {"eventId":1,"type":"message.delta","runId":"run_01HQU...","payload":{"delta":"Great question! Here's a"}}
event: message.delta
data: {"eventId":2,"type":"message.delta","runId":"run_01HQU...","payload":{"delta":" structured 45-minute morning reporting workflow"}}
event: message.delta
data: {"eventId":3,"type":"message.delta","runId":"run_01HQU...","payload":{"delta":" that balances exercise, mindfulness, and preparation:\n\n"}}
event: message.delta
data: {"eventId":4,"type":"message.delta","runId":"run_01HQU...","payload":{"delta":"1. **Wake up + hydrate** (2 min)\n"}}
event: message.delta
data: {"eventId":5,"type":"message.delta","runId":"run_01HQU...","payload":{"delta":"2. **Stretching** (5 min)\n"}}
event: message.delta
data: {"eventId":6,"type":"message.delta","runId":"run_01HQU...","payload":{"delta":"3. **Bodyweight workout** (20 min)\n"}}
event: message.delta
data: {"eventId":7,"type":"message.delta","runId":"run_01HQU...","payload":{"delta":"4. **Shower** (10 min)\n"}}
event: message.delta
data: {"eventId":8,"type":"message.delta","runId":"run_01HQU...","payload":{"delta":"5. **Journaling** (8 min)\n"}}
event: message.completed
data: {"eventId":9,"type":"message.completed","runId":"run_01HQU...","payload":{"messageId":"msg_01HQU...","content":"Great question! Here's a structured 45-minute morning reporting workflow..."}}Event Types
| Event | Description |
|---|---|
message.delta | A chunk of the response content |
message.completed | Streamed assistant content is complete |
tool.* | Tool-card, progress, approval, and result events |
run.error / run.failed | An error occurred during generation |
run.settlement.completed | Run is fully settled and terminal |
Step 5: List Conversation History
Retrieve the full conversation thread for a session:
curl -s "https://api.chainabit.com/api/v1/ai/sessions/$SESSION_ID/messages" \
-H "Authorization: Bearer $TOKEN"Response:
{
"data": [
{
"id": "msg_01HQT...",
"role": "user",
"content": "I want to build a morning reporting workflow. I have 45 minutes before work. What activities should I include?",
"createdAt": "2026-03-17T10:01:00.000Z"
},
{
"id": "msg_01HQU...",
"role": "assistant",
"content": "Great question! Here's a structured 45-minute morning reporting workflow...",
"createdAt": "2026-03-17T10:01:05.000Z"
}
],
"meta": {
"total": 2
}
}Step 6: Create an AI Run
AI runs execute a specific, entitlement-gated feature rather than a free-form session — the feature key goes in the path, and the request is a chat-style messages array rather than an arbitrary input object:
GET /ai/features lists every feature key your plan has access to. Optional body fields: temperature, maxOutputTokens, idempotencyKey, provider, and effortMode (basic | thinking | pro).
Response (201 Created, or 200 OK if this exact request is still queued/running from an earlier identical call):
{
"data": {
"requestId": "req_01HQV...",
"runId": "run_01HQV...",
"result": {
"finishReason": "queued"
}
}
}Save the run ID:
export RUN_ID="run_01HQV..."GET /ai/runs/$RUN_ID returns the run's current status once it's no longer queued.
Step 7: Stream Run Output
Stream the AI run output the same way you stream messages:
Output — as with the message stream in Step 4, the first frame is a stream.connected preamble, and every event after it is a numbered envelope (id: line plus an eventId/type/runId/payload JSON body — timestamp and v fields omitted below for brevity, see Step 4):
event: stream.connected
data: {"runId": "run_01HQV..."}
id: 1
event: run.started
data: {"eventId":1,"type":"run.started","runId":"run_01HQV...","payload":{"runId":"run_01HQV..."}}
id: 2
event: message.delta
data: {"eventId":2,"type":"message.delta","runId":"run_01HQV...","payload":{"delta":"## Weekly Summary: March 10-16\n\n"}}
id: 3
event: message.delta
data: {"eventId":3,"type":"message.delta","runId":"run_01HQV...","payload":{"delta":"**Workout Chain:** 5/7 days completed (71%)\n"}}
id: 4
event: message.completed
data: {"eventId":4,"type":"message.completed","runId":"run_01HQV...","payload":{"runId":"run_01HQV...","messageId":"msg_01HQW...","content":"## Weekly Summary: March 10-16\n\n..."}}
id: 5
event: run.settlement.completed
data: {"eventId":5,"type":"run.settlement.completed","runId":"run_01HQV...","payload":{"status":"completed"}}Handling Connection Drops
SSE connections can drop due to network issues. To handle reconnection:
- Track the last event you received
- When the connection drops, reconnect to the same endpoint
- The server will resume from where it left off if the generation is still in progress
# If the connection drops, simply reconnect:
curl -N "https://api.chainabit.com/api/v1/ai/sessions/$SESSION_ID/messages/$MESSAGE_ID/stream" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: text/event-stream"If you receive run.settlement.completed, run.failed, or run.error, the stream is terminal and no reconnection is needed.
Summary
In this tutorial you:
- Listed available AI models on your plan
- Created an AI session for a conversation thread
- Sent a message and captured its ID
- Streamed the AI response via SSE in real time
- Retrieved the full conversation history
- Created an AI run for a specific feature
- Streamed the run output with the same SSE pattern
Next Steps
- How to Stream AI Responses for advanced streaming patterns and JavaScript examples
- Create an AI Agent to build a reusable agent that can run sessions for you
- API Reference for the complete AI endpoints documentation