API v1.0 — Stable

KlairoAI API
Reference

Integrate Aria AI, automations, CRM contacts, and real-time webhooks into your stack. All responses are JSON. Authentication uses industry-standard JWT Bearer tokens.

Getting Started

Overview

The KlairoAI REST API lets you programmatically control your AI employee — Aria — and all surrounding infrastructure. Build custom integrations, connect your own CRM, trigger automations, or stream AI responses directly in your product.

Base URL https://api.klairoai.com/v1
🔒
JWT Authentication
Obtain a token once, attach it as a Bearer header on every request.
JSON Responses
All endpoints return application/json. Errors follow a consistent shape.
🔗
Webhooks
Receive real-time event pushes to your own server URL — no polling needed.
🤖
Aria AI
Chat endpoint gives direct access to Aria with full conversation context.
🔄
Automations
Full CRUD + manual trigger for all your AI-powered workflow automations.
📇
CRM / Contacts
Sync leads and clients bi-directionally with your existing tools.
ℹ️
All requests must be made over HTTPS. HTTP requests will be rejected with 426 Upgrade Required.

Error format

Every error response follows this consistent shape:

JSON
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Bearer token is missing or invalid.",
    "status": 401
  }
}

Rate limits

PlanRequests / minuteChat messages / day
Starter60500
Growth3005,000
EnterpriseCustomUnlimited
Authentication

Authentication

KlairoAI uses JWT (JSON Web Tokens). Exchange your credentials for a token, then include it in the Authorization header of every subsequent request.

Tokens expire after 24 hours. Re-authenticate when you receive a 401 response. Store tokens securely — never expose them in client-side code or version control.
ℹ️
Use the Authorization: Bearer <token> header on all protected endpoints.
POST /api/auth/login Obtain a JWT token

Headers

HTTP
Content-Type: application/json

Body

FieldTypeRequiredDescription
emailstringrequiredYour KlairoAI account email.
passwordstringrequiredAccount password.
JSON
{
  "email": "you@company.com",
  "password": "supersecret123"
}
JSON — 200 OK
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_at": "2026-03-12T11:22:00Z",
  "user": {
    "id": "usr_01JNABCXYZ",
    "email": "you@company.com",
    "name": "Daniel Kmit",
    "plan": "growth"
  }
}
CodeMeaning
200Token issued successfully.
400Missing or malformed fields.
401Invalid credentials.
500Internal server error.
POST /api/auth/refresh Refresh an expiring token

API Key Authentication

For server-to-server integrations, you can authenticate using an API key instead of a JWT token. API keys are generated in your portal dashboard and provide long-lived access without needing to exchange credentials.

🔑
API keys use the same Authorization: Bearer header as JWT tokens. The API automatically detects keys by their kl_live_ prefix.
⚠️
API keys are shown only once when created. Store them securely — never commit keys to version control or expose them in client-side code. Keys are rate-limited by plan: Free (10/mo), Starter (100/mo), Pro (1,000/mo).

Usage

HTTP Header
Authorization: Bearer kl_live_a1b2c3d4e5f6...

Example — Chat with Aria using API key

cURL
curl -X POST https://klairoai.com/api/chat \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer kl_live_a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef12345678" \
  -d '{
    "message": "Draft a follow-up email for the Smith proposal",
    "action": "chat"
  }'

Validate an API key

cURL
curl https://klairoai.com/api/keys?action=validate \
  -H "Authorization: Bearer kl_live_YOUR_API_KEY"
JSON — 200 OK
{
  "valid": true,
  "user_id": "usr_01JNABCXYZ",
  "email": "you@company.com",
  "plan": "pro",
  "key_name": "Production App",
  "usage": 42,
  "limit": 1000
}
Aria AI

Chat with Aria

Send messages to Aria and receive intelligent AI responses. Aria has full context of your business, clients, and automations. Supports multi-turn conversations via conversation_id.

⚠️
Rate limited: Chat messages are counted against your plan's daily quota. Streaming responses use Server-Sent Events — set "stream": true to enable.
POST /api/chat Send a message to Aria

Headers

HTTP
Authorization: Bearer <token>
Content-Type: application/json

Body Parameters

FieldTypeRequiredDescription
messagestringrequiredThe user message to send to Aria.
conversation_idstringoptionalID of an existing conversation. Omit to start a new one.
contextobjectoptionalExtra business context to inject (e.g. contact data).
streambooleanoptionalStream response via SSE. Default: false.
JSON
{
  "message": "Summarise the last 3 client follow-ups and suggest next steps.",
  "conversation_id": "conv_01JNXYZ987",
  "context": {
    "contact_id": "cnt_01JNABC123"
  },
  "stream": false
}
JSON — 200 OK
{
  "conversation_id": "conv_01JNXYZ987",
  "message_id": "msg_01JNA000XYZ",
  "role": "assistant",
  "content": "Here's a summary of the last 3 follow-ups with Acme Corp...",
  "created_at": "2026-03-11T11:22:00Z",
  "usage": {
    "prompt_tokens": 420,
    "completion_tokens": 215,
    "total_tokens": 635
  }
}
CodeMeaning
200Response generated successfully.
400Missing message field.
401Invalid or expired token.
429Daily message quota exceeded.
503AI provider temporarily unavailable.
Automations

Automations

Automations are AI-powered workflows — email sequences, lead follow-ups, scheduling chains, and more. Full CRUD support plus a manual trigger endpoint for immediate execution.

GET /api/automations List all automations

Headers

HTTP
Authorization: Bearer <token>

Query Parameters

FieldTypeRequiredDescription
statusstringoptionalactive | paused | draft. Filter by status.
limitintegeroptionalMax results (default: 20, max: 100).
offsetintegeroptionalPagination offset (default: 0).
JSON — 200 OK
{
  "data": [
    {
      "id": "auto_01JNABC001",
      "name": "New Lead Follow-up",
      "status": "active",
      "trigger": "contact_created",
      "steps": 4,
      "last_run": "2026-03-10T09:15:00Z",
      "created_at": "2026-02-01T08:00:00Z"
    }
  ],
  "total": 12,
  "limit": 20,
  "offset": 0
}
CodeMeaning
200List returned.
401Unauthorized.
POST /api/automations Create an automation
PATCH /api/automations/:id Update an automation
DELETE /api/automations/:id Delete an automation
POST /api/automations/:id/trigger Manually trigger an automation
Notifications

Notifications

Retrieve in-app notifications for your account and mark them as read. Notifications are generated by Aria, automation runs, system events, and webhook deliveries.

GET /api/notifications List notifications

Headers

HTTP
Authorization: Bearer <token>

Query Parameters

FieldTypeRequiredDescription
unreadbooleanoptionalReturn only unread notifications.
limitintegeroptionalMax results (default: 20).
JSON — 200 OK
{
  "data": [
    {
      "id": "ntf_01JNXYZ555",
      "type": "automation_completed",
      "title": "Automation run complete",
      "body": "Proposal Follow-up Sequence finished for Alex at Acme Corp.",
      "read": false,
      "metadata": {
        "automation_id": "auto_01JNABC999",
        "run_id": "run_01JNXYZ111"
      },
      "created_at": "2026-03-11T11:30:00Z"
    }
  ],
  "unread_count": 4,
  "total": 18
}
CodeMeaning
200List returned.
401Unauthorized.
PATCH /api/notifications/read Mark notifications as read
CRM / Contacts

Contacts

Sync your leads and clients with KlairoAI. Aria uses contact context to personalise outreach, proposals, and follow-ups. All contact fields are stored as schemaless metadata.

GET /api/contacts List contacts

Headers

HTTP
Authorization: Bearer <token>

Query Parameters

FieldTypeRequiredDescription
searchstringoptionalFull-text search across name, email, company.
tagstringoptionalFilter by tag (e.g. prospect, client).
limitintegeroptionalDefault: 20. Max: 100.
offsetintegeroptionalPagination offset.
JSON — 200 OK
{
  "data": [
    {
      "id": "cnt_01JNABC123",
      "name": "Alex Johnson",
      "email": "alex@acmecorp.com",
      "company": "Acme Corp",
      "tags": ["prospect", "proposal-sent"],
      "metadata": {
        "deal_value": 12000,
        "source": "cold-email"
      },
      "created_at": "2026-02-15T08:00:00Z",
      "updated_at": "2026-03-10T14:30:00Z"
    }
  ],
  "total": 87,
  "limit": 20,
  "offset": 0
}
CodeMeaning
200Contact list returned.
401Unauthorized.
POST /api/contacts Create a contact
PATCH /api/contacts/:id Update a contact
Webhooks

Webhooks

KlairoAI pushes real-time events to your server when things happen — automation runs complete, contacts are created, Aria generates a response, or a message is sent. Register an HTTPS endpoint and we'll deliver signed JSON payloads instantly.

🔐
All webhook deliveries include an X-KlairoAI-Signature header — an HMAC-SHA256 of the raw body signed with your webhook secret. Always verify this before trusting the payload.

Event types

EventDescription
automation.runAn automation was triggered (manual or scheduled).
aria.messageAria generated a new response in a conversation.
plan.changedThe user's subscription plan was changed.
usage.limit_reachedA usage limit was hit (daily messages, AI generations, etc.).
test.pingTest delivery triggered from the portal.

Delivery headers

HeaderDescription
X-KlairoAI-EventThe event type (e.g. automation.run).
X-KlairoAI-DeliveryUnique delivery UUID for idempotency.
X-KlairoAI-SignatureHMAC-SHA256 signature: sha256=<hex>.

Retry policy

If your endpoint returns a non-2xx response, KlairoAI retries with exponential backoff: immediate → 5 min → 30 min → 2 hours → 8 hours. After 5 attempts, the delivery is marked as failed. All delivery attempts are logged and visible in your portal.

Plan limits

PlanMax Webhooks
Free1
Starter2
Pro / Full Stack5

Payload shape

JSON — Example: automation.run.completed
{
  "event": "automation.run.completed",
  "event_id": "evt_01JNXYZ222",
  "created_at": "2026-03-11T11:30:00Z",
  "data": {
    "run_id": "run_01JNXYZ111",
    "automation_id": "auto_01JNABC999",
    "automation_name": "Proposal Follow-up Sequence",
    "contact_id": "cnt_01JNABC123",
    "status": "completed",
    "steps_run": 2,
    "duration_ms": 4200
  }
}

Signature verification

Node.js — Express example
const crypto = require('crypto');

app.post('/webhook/klairo', express.raw({ type: '*/*' }), (req, res) => {
  const sig     = req.headers['x-klairoai-signature'];
  const secret  = process.env.KLAIRO_WEBHOOK_SECRET;
  const digest  = crypto.createHmac('sha256', secret)
                        .update(req.body)
                        .digest('hex');

  if (sig !== `sha256=${digest}`) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(req.body);
  console.log('Received event:', event.event);
  res.sendStatus(200);
});
POST /api/webhooks Register a webhook endpoint

Headers

HTTP
Authorization: Bearer <token>
Content-Type: application/json
FieldTypeRequiredDescription
urlstringrequiredYour HTTPS endpoint URL.
eventsarrayrequiredEvent types to subscribe to. Use ["*"] for all.
descriptionstringoptionalLabel for your own reference.
JSON
{
  "url": "https://myapp.com/webhook/klairo",
  "events": [
    "automation.run.completed",
    "contact.created",
    "chat.message.created"
  ],
  "description": "Production webhook receiver"
}
JSON — 201 Created
{
  "id": "wh_01JNXYZ333",
  "url": "https://myapp.com/webhook/klairo",
  "events": ["automation.run.completed", "contact.created", "chat.message.created"],
  "secret": "whsec_K9xB2mLvQ3...",
  "status": "active",
  "created_at": "2026-03-11T11:22:00Z"
}
⚠️
The secret is shown only once. Store it immediately in your environment variables — it cannot be retrieved again.
CodeMeaning
201Webhook registered.
400Invalid URL or events list.
401Unauthorized.
GET /api/webhooks List registered webhooks
DELETE /api/webhooks/:id Remove a webhook
POST /api/webhooks?action=test Send a test delivery
GET /api/webhooks?action=deliveries&id=:id Delivery history (last 50)
Analytics

Usage Analytics

Retrieve aggregated usage statistics for your KlairoAI account — message volume, automation runs, contact activity, and API call counts. Data is available by day, week, or month.

GET /api/analytics Get usage analytics

Headers

HTTP
Authorization: Bearer <token>

Query Parameters

FieldTypeRequiredDescription
periodstringoptionalday | week | month. Default: month.
fromstringoptionalISO 8601 start date e.g. 2026-03-01.
tostringoptionalISO 8601 end date (inclusive).
cURL
curl https://api.klairoai.com/v1/analytics?period=month&from=2026-03-01 \
  -H "Authorization: Bearer <token>"
JSON — 200 OK
{
  "period": "month",
  "from": "2026-03-01",
  "to": "2026-03-31",
  "summary": {
    "chat_messages": 1842,
    "automation_runs": 314,
    "contacts_created": 57,
    "api_calls": 2987,
    "webhooks_delivered": 289
  },
  "daily": [
    {
      "date": "2026-03-11",
      "chat_messages": 63,
      "automation_runs": 11,
      "contacts_created": 2,
      "api_calls": 98
    }
  ],
  "quota": {
    "plan": "growth",
    "chat_limit_daily": 5000,
    "chat_used_today": 63,
    "api_limit_per_minute": 300
  }
}
CodeMeaning
200Analytics data returned.
400Invalid date range or period.
401Unauthorized.
403Analytics not available on your plan.
Users

Current User

Retrieve profile and plan information for the authenticated user. Useful for verifying tokens and checking plan limits in your integration.

GET /api/users/me Get current user info

Headers

HTTP
Authorization: Bearer <token>
cURL
curl https://api.klairoai.com/v1/users/me \
  -H "Authorization: Bearer <token>"
JSON — 200 OK
{
  "id": "usr_01JNABCXYZ",
  "name": "Daniel Kmit",
  "email": "daniel@mycompany.com",
  "avatar_url": "https://klairoai.com/avatars/usr_01JNABCXYZ.jpg",
  "plan": {
    "id": "growth",
    "label": "Growth",
    "status": "active",
    "renews_at": "2026-04-01T00:00:00Z"
  },
  "quota": {
    "chat_limit_daily": 5000,
    "api_limit_per_minute": 300,
    "automations_max": 50
  },
  "created_at": "2026-01-15T09:00:00Z",
  "last_seen_at": "2026-03-11T11:00:00Z"
}
CodeMeaning
200User profile returned.
401Invalid or expired token.
Reference

Error Codes

All errors follow a consistent JSON shape. The code field is a machine-readable string you can use to handle errors programmatically.

JSON — Error shape
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests. Slow down and retry after 1 minute.",
    "status": 429,
    "retry_after": 60
  }
}
HTTP StatusCodeDescription
200 OK Request succeeded.
201 CREATED Resource created successfully.
204 NO_CONTENT Delete succeeded — no body returned.
400 BAD_REQUEST Missing or invalid parameters. Check the message field for details.
401 UNAUTHORIZED Bearer token missing, invalid, or expired. Re-authenticate to get a new token.
403 FORBIDDEN You are authenticated but lack permission for this action (e.g. plan restriction or ownership mismatch).
404 NOT_FOUND The requested resource does not exist or you don't have access to it.
409 CONFLICT Duplicate resource (e.g. email already registered) or state conflict (e.g. triggering a paused automation).
422 UNPROCESSABLE Request is well-formed but semantically invalid (e.g. invalid date range).
429 RATE_LIMIT_EXCEEDED Too many requests. The response includes a Retry-After header with the number of seconds to wait.
500 INTERNAL_ERROR Unexpected server error. If it persists, contact api@klairoai.com.
503 SERVICE_UNAVAILABLE Downstream AI provider is temporarily unavailable. Retry with exponential backoff.
💡
Retry strategy: For 429 errors, wait the number of seconds in the Retry-After header before retrying. For 5xx errors, use exponential backoff starting at 1 second.
Reference

Rate Limits

Rate limits are applied per account. When exceeded, you'll receive a 429 Too Many Requests response with a Retry-After header indicating seconds until the limit resets.

PlanAPI requests / minuteChat messages / dayAutomations max
Starter6050010
Growth3005,00050
EnterpriseCustomUnlimitedUnlimited

Rate limit headers

Every response includes these headers so you can track consumption:

HeaderDescription
X-RateLimit-LimitMax requests allowed in the current window.
X-RateLimit-RemainingRequests remaining in the current window.
X-RateLimit-ResetUnix timestamp when the window resets.
Retry-AfterSeconds to wait before retrying (only on 429).
SDKs

SDKs & Libraries

Official KlairoAI SDKs are in active development. Until they ship, use the REST API directly — it's fully documented above and works with any HTTP client.

🟨
Node.js / TypeScript Coming soon
Full TypeScript types, automatic token refresh, streaming support, and retry logic built in.
🐍
Python Coming soon
Async-first with asyncio support. Pydantic models for all request/response types.
🔴
Ruby Planned
Native gem with Faraday integration and Rails-friendly helpers.

Using the API today — Node.js example

JavaScript (fetch)
const KLAIRO_TOKEN = process.env.KLAIRO_API_TOKEN;
const BASE = 'https://api.klairoai.com/v1';

async function chatWithAria(message) {
  const res = await fetch(`${BASE}/chat`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${KLAIRO_TOKEN}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ message })
  });

  if (!res.ok) {
    const err = await res.json();
    throw new Error(err.error.message);
  }

  return res.json();
}

const reply = await chatWithAria('Summarise today\'s leads.');
console.log(reply.content);

Python example

Python (requests)
import os, requests

TOKEN = os.environ["KLAIRO_API_TOKEN"]
BASE  = "https://api.klairoai.com/v1"

def chat_with_aria(message: str) -> dict:
    r = requests.post(
        f"{BASE}/chat",
        headers={"Authorization": f"Bearer {TOKEN}"},
        json={"message": message},
        timeout=30
    )
    r.raise_for_status()
    return r.json()

reply = chat_with_aria("List all automations currently active.")
print(reply["content"])
📬
Interested in an early SDK preview? Email api@klairoai.com and we'll add you to the beta list.
© 2026 KlairoAI. API v1.0
Privacy Terms api@klairoai.com