Skip to content

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
  • curl available in your terminal
  • A plan that includes AI credits (check your balance at /wallet/me)

Set your environment variables:

bash
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:

bash
curl -s "https://api.chainabit.com/api/v1/ai/providers" \
  -H "Authorization: Bearer $TOKEN"

Response includes an isAccessible flag per provider:

json
{
  "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 google is accessible. Paid plans unlock additional providers.


Step 2: Create a New AI Session ​

A session holds a conversation thread:

bash
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:

json
{
  "data": {
    "id": "session_01HQS...",
    "title": "Fitness coaching",
    "status": "active",
    "startedAt": "2026-03-17T10:00:00.000Z"
  }
}

Save the session ID:

bash
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:

bash
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"
  }'
FieldValuesDescription
providergoogle, openai, anthropic, mistral, and others — see GET /ai/providers for the full, current listProvider to use. Defaults to google. Every provider other than google requires a paid plan with that provider's entitlement.
effortModebasic, thinking, proModel tier. basic = fast, thinking = balanced, pro = most capable.

Both fields are optional — omitting them uses your plan's default (Google, basic).

Response:

json
{
  "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:

bash
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:

bash
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 ​

EventDescription
message.deltaA chunk of the response content
message.completedStreamed assistant content is complete
tool.*Tool-card, progress, approval, and result events
run.error / run.failedAn error occurred during generation
run.settlement.completedRun is fully settled and terminal

Step 5: List Conversation History ​

Retrieve the full conversation thread for a session:

bash
curl -s "https://api.chainabit.com/api/v1/ai/sessions/$SESSION_ID/messages" \
  -H "Authorization: Bearer $TOKEN"

Response:

json
{
  "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):

json
{
  "data": {
    "requestId": "req_01HQV...",
    "runId": "run_01HQV...",
    "result": {
      "finishReason": "queued"
    }
  }
}

Save the run ID:

bash
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:

  1. Track the last event you received
  2. When the connection drops, reconnect to the same endpoint
  3. The server will resume from where it left off if the generation is still in progress
bash
# 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:

  1. Listed available AI models on your plan
  2. Created an AI session for a conversation thread
  3. Sent a message and captured its ID
  4. Streamed the AI response via SSE in real time
  5. Retrieved the full conversation history
  6. Created an AI run for a specific feature
  7. Streamed the run output with the same SSE pattern

Next Steps ​

Built with purpose.