Response Envelope
Every response from the Chainabit API follows a consistent envelope format. This makes it straightforward to handle responses generically in your client code, regardless of which endpoint you are calling.
Envelope Structure
interface ApiResponseEnvelope<T> {
data?: T;
meta?: ApiMeta;
error?: ApiError;
}A successful response always includes data and typically includes meta. An error response includes error and omits data.
Meta Object
interface ApiMeta {
requestId: string; // Unique identifier for this request (useful for support)
durationMs: number; // Server-side processing time in milliseconds
limit?: number; // Page size (list endpoints only)
offset?: number; // Current offset (offset-paginated endpoints only)
total?: number; // Total record count (offset-paginated endpoints only)
hasNextPage?: boolean; // Whether more records exist
nextCursor?: string; // Cursor for next page (cursor-paginated endpoints only)
}Error Object
interface ApiError {
code: string; // Machine-readable error code (e.g., "VALIDATION_ERROR")
message: string; // Human-readable description
details?: any; // Additional context (field-level validation errors, etc.)
}Examples
Single Record Success
GET /api/v1/ai/sessions/sess-abc-123 returns 200 OK:
{
"data": {
"id": "sess-abc-123",
"title": "Research Assistant",
"status": "active",
"createdAt": "2026-01-15T08:00:00.000Z"
},
"meta": {
"requestId": "req_7f3a9b2c",
"durationMs": 12
}
}Paginated List Success (Offset-based)
GET /api/v1/ai/sessions?limit=2&offset=0 returns 200 OK:
{
"data": [
{
"id": "sess-abc-123",
"title": "Research Assistant",
"status": "active"
},
{
"id": "sess-def-456",
"title": "Developer Pipeline",
"status": "active"
}
],
"meta": {
"requestId": "req_8e4b0c3d",
"durationMs": 18,
"limit": 2,
"offset": 0,
"total": 12,
"hasNextPage": true
}
}Cursor-Paginated List Success
GET /api/v1/billing/invoices?limit=2 returns 200 OK:
{
"data": [
{
"id": "inv_001",
"amount": 1999,
"currency": "usd",
"status": "paid",
"createdAt": "2026-03-01T00:00:00.000Z"
},
{
"id": "inv_002",
"amount": 1999,
"currency": "usd",
"status": "paid",
"createdAt": "2026-02-01T00:00:00.000Z"
}
],
"meta": {
"requestId": "req_9f5c1d4e",
"durationMs": 22,
"limit": 2,
"hasNextPage": true,
"nextCursor": "eyJpZCI6Imludl8wMDIifQ=="
}
}To fetch the next page, include the cursor: GET /api/v1/billing/invoices?limit=2&cursor=eyJpZCI6Imludl8wMDIifQ==
Validation Error (400)
POST /api/v1/ai/sessions with invalid body returns 400 Bad Request:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": [
{
"field": "name",
"message": "name must be a string"
},
{
"field": "cadence",
"message": "cadence must be one of: daily, weekly, custom"
}
]
},
"meta": {
"requestId": "req_1a2b3c4d",
"durationMs": 3
}
}Rate Limit Error (429)
Any endpoint when the rate limit is exceeded returns 429 Too Many Requests:
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please retry after the indicated time.",
"details": {
"retryAfter": 45
}
},
"meta": {
"requestId": "req_5e6f7g8h",
"durationMs": 1
}
}The retryAfter value is in seconds. You should also check the Retry-After HTTP header.