Skip to content

Making Requests

This page covers the conventions and patterns you need to know when interacting with the Chainabit API: base URL, headers, response format, pagination, error handling, and idempotency.


Base URL

All endpoints are relative to:

https://api.chainabit.com/api/v1

For example, the AI sessions endpoint resolves to {API_URL}/api/v1/ai/sessions.


Environment Variables

Set these variables before running any example on this page:

bash
export BASE_URL="https://api.chainabit.com/api/v1"
export TOKEN="your-access-token"

Required Headers

Every request should include:

HeaderValueRequired
Content-Typeapplication/jsonFor POST, PUT, and PATCH requests
AuthorizationBearer <accessToken>For all authenticated endpoints

Response Envelope

Every API response follows a consistent envelope structure:

json
{
  "data": { ... },
  "meta": { ... },
  "error": null
}
FieldDescription
dataThe requested resource or result. null when an error occurs.
metaAdditional metadata such as pagination info. null when not applicable.
errorError details. null when the request succeeds.

For a deeper explanation of the envelope design, see Response Envelope.

Successful Response

json
{
  "data": {
    "id": "c9f8e7d6-5432-10fe-dcba-0987654321fe",
    "title": "Research Assistant",
    "status": "active"
  },
  "meta": null,
  "error": null
}

Error Response

json
{
  "data": null,
  "meta": null,
  "error": {
    "statusCode": 404,
    "message": "Chain not found",
    "code": "NOT_FOUND"
  }
}

Pagination

List endpoints support offset-based pagination with two query parameters:

ParameterDefaultDescription
limit20Number of items to return (max varies by endpoint).
offset0Number of items to skip.

Example

bash
curl "https://api.chainabit.com/api/v1/ai/sessions?limit=10&offset=20" \
  -H "Authorization: Bearer $TOKEN"
js
const response = await fetch(
  `${BASE_URL}/ai/sessions?limit=10&offset=20`,
  {
    headers: { Authorization: `Bearer ${TOKEN}` },
  }
);
const { data, meta } = await response.json();
python
import requests

response = requests.get(
    f"{BASE_URL}/ai/sessions",
    params={"limit": 10, "offset": 20},
    headers={"Authorization": f"Bearer {TOKEN}"},
)
result = response.json()
data, meta = result["data"], result["meta"]
txt
Open AI → GET List Sessions
Add query params: limit=10, offset=20

Response

json
{
  "data": [
    { "id": "...", "title": "Developer Pipeline" },
    { "id": "...", "title": "Research Assistant" }
  ],
  "meta": {
    "total": 42,
    "limit": 10,
    "offset": 20
  },
  "error": null
}

Use meta.total to calculate the number of pages or determine whether more items exist. For full pagination details, see Pagination.


Error Handling

Always check the error field in the response. Common HTTP status codes:

StatusMeaning
400Bad request -- invalid or missing parameters.
401Unauthorized -- missing or expired token.
403Forbidden -- insufficient permissions or captcha failure.
404Not found -- the resource does not exist.
409Conflict -- duplicate resource or idempotency key collision.
422Unprocessable entity -- validation error.
429Too many requests -- rate limit exceeded.
500Internal server error.

Rate Limiting

When you exceed the rate limit, the API returns 429 Too Many Requests with a Retry-After header indicating how many seconds to wait:

json
{
  "data": null,
  "meta": null,
  "error": {
    "statusCode": 429,
    "message": "Rate limit exceeded. Try again in 30 seconds.",
    "code": "RATE_LIMITED"
  }
}

Best practice: implement exponential backoff and respect the Retry-After header. For rate limit tiers and quotas, see Rate Limiting.

For the full error code reference, see Errors.


Idempotency

Some mutating endpoints (such as creating transactions or logging events) accept an Idempotency-Key header. Sending the same idempotency key for the same endpoint returns the original response without creating a duplicate resource.

bash
curl -X POST https://api.chainabit.com/api/v1/ai/sessions \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -d '{"title": "Pipeline session"}'
js
const response = await fetch(`${BASE_URL}/ai/sessions`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${TOKEN}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({ title: 'Pipeline session' }),
});
const { data } = await response.json();
python
import requests
import uuid

response = requests.post(
    f"{BASE_URL}/ai/sessions",
    headers={
        "Authorization": f"Bearer {TOKEN}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={"title": "Pipeline session"},
)
data = response.json()["data"]
txt
Open AI → POST Create Session
Set Idempotency-Key header to {{$randomUUID}}

Guidelines:

  • Use a UUID v4 as the idempotency key.
  • Keys are scoped to your account and the specific endpoint.
  • Keys expire after 24 hours. After that, the same key can be reused.
  • If the original request is still being processed, a subsequent request with the same key returns 409 Conflict.

Full Request-Response Example

Here is a complete example that creates an AI session, handles potential errors, and demonstrates proper header usage:

bash
curl -s -w "\nHTTP_STATUS:%{http_code}" \
  -X POST https://api.chainabit.com/api/v1/ai/sessions \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7" \
  -d '{
    "title": "Research Assistant"
  }'

Success -- 201 Created

json
{
  "data": {
    "id": "sess_01HQ3K5N2P4R7T9V1X3Z5A7C9E",
    "title": "Research Assistant",
    "status": "active",
    "createdAt": "2026-05-04T20:00:00.000Z"
  },
  "meta": null,
  "error": null
}

Validation error -- 422 Unprocessable Entity

json
{
  "data": null,
  "meta": null,
  "error": {
    "statusCode": 422,
    "message": "Validation failed",
    "code": "VALIDATION_ERROR",
    "details": [
      {
        "field": "title",
        "message": "title must be a string and is required"
      }
    ]
  }
}

Token expired -- 401 Unauthorized

json
{
  "data": null,
  "meta": null,
  "error": {
    "statusCode": 401,
    "message": "Unauthorized",
    "code": "UNAUTHORIZED"
  }
}

When you receive a 401, refresh your token (see Authentication) and retry the request.


Next Steps

Built with purpose.