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.
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.
https://api.klairoai.com/v1
application/json. Errors follow a consistent shape.426 Upgrade Required.Error format
Every error response follows this consistent shape:
{
"error": {
"code": "UNAUTHORIZED",
"message": "Bearer token is missing or invalid.",
"status": 401
}
}
Rate limits
| Plan | Requests / minute | Chat messages / day |
|---|---|---|
| Starter | 60 | 500 |
| Growth | 300 | 5,000 |
| Enterprise | Custom | Unlimited |
Authentication
KlairoAI uses JWT (JSON Web Tokens). Exchange your credentials for a token, then include it in the
Authorization header of every subsequent request.
401 response.
Store tokens securely — never expose them in client-side code or version control.Authorization: Bearer <token> header on all protected endpoints./api/auth/login
Obtain a JWT token
▾
Headers
Content-Type: application/json
Body
| Field | Type | Required | Description |
|---|---|---|---|
email | string | required | Your KlairoAI account email. |
password | string | required | Account password. |
{
"email": "you@company.com",
"password": "supersecret123"
}
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_at": "2026-03-12T11:22:00Z",
"user": {
"id": "usr_01JNABCXYZ",
"email": "you@company.com",
"name": "Daniel Kmit",
"plan": "growth"
}
}
| Code | Meaning |
|---|---|
| 200 | Token issued successfully. |
| 400 | Missing or malformed fields. |
| 401 | Invalid credentials. |
| 500 | Internal server error. |
/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.
Authorization: Bearer header as JWT tokens. The API automatically
detects keys by their kl_live_ prefix.Usage
Authorization: Bearer kl_live_a1b2c3d4e5f6...
Example — Chat with Aria using API key
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 https://klairoai.com/api/keys?action=validate \
-H "Authorization: Bearer kl_live_YOUR_API_KEY"
{
"valid": true,
"user_id": "usr_01JNABCXYZ",
"email": "you@company.com",
"plan": "pro",
"key_name": "Production App",
"usage": 42,
"limit": 1000
}
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.
"stream": true to enable./api/chat
Send a message to Aria
▾
Headers
Authorization: Bearer <token>
Content-Type: application/json
Body Parameters
| Field | Type | Required | Description |
|---|---|---|---|
message | string | required | The user message to send to Aria. |
conversation_id | string | optional | ID of an existing conversation. Omit to start a new one. |
context | object | optional | Extra business context to inject (e.g. contact data). |
stream | boolean | optional | Stream response via SSE. Default: false. |
{
"message": "Summarise the last 3 client follow-ups and suggest next steps.",
"conversation_id": "conv_01JNXYZ987",
"context": {
"contact_id": "cnt_01JNABC123"
},
"stream": false
}
{
"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
}
}
| Code | Meaning |
|---|---|
| 200 | Response generated successfully. |
| 400 | Missing message field. |
| 401 | Invalid or expired token. |
| 429 | Daily message quota exceeded. |
| 503 | AI provider temporarily unavailable. |
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.
/api/automations
List all automations
▾
Headers
Authorization: Bearer <token>
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
status | string | optional | active | paused | draft. Filter by status. |
limit | integer | optional | Max results (default: 20, max: 100). |
offset | integer | optional | Pagination offset (default: 0). |
{
"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
}
| Code | Meaning |
|---|---|
| 200 | List returned. |
| 401 | Unauthorized. |
/api/automations
Create an automation
▾
/api/automations/:id
Update an automation
▾
/api/automations/:id
Delete an automation
▾
/api/automations/:id/trigger
Manually trigger an automation
▾
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.
/api/notifications
List notifications
▾
Headers
Authorization: Bearer <token>
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
unread | boolean | optional | Return only unread notifications. |
limit | integer | optional | Max results (default: 20). |
{
"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
}
| Code | Meaning |
|---|---|
| 200 | List returned. |
| 401 | Unauthorized. |
/api/notifications/read
Mark notifications as read
▾
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.
/api/contacts
List contacts
▾
Headers
Authorization: Bearer <token>
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
search | string | optional | Full-text search across name, email, company. |
tag | string | optional | Filter by tag (e.g. prospect, client). |
limit | integer | optional | Default: 20. Max: 100. |
offset | integer | optional | Pagination offset. |
{
"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
}
| Code | Meaning |
|---|---|
| 200 | Contact list returned. |
| 401 | Unauthorized. |
/api/contacts
Create a contact
▾
/api/contacts/:id
Update a contact
▾
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.
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
| Event | Description |
|---|---|
automation.run | An automation was triggered (manual or scheduled). |
aria.message | Aria generated a new response in a conversation. |
plan.changed | The user's subscription plan was changed. |
usage.limit_reached | A usage limit was hit (daily messages, AI generations, etc.). |
test.ping | Test delivery triggered from the portal. |
Delivery headers
| Header | Description |
|---|---|
X-KlairoAI-Event | The event type (e.g. automation.run). |
X-KlairoAI-Delivery | Unique delivery UUID for idempotency. |
X-KlairoAI-Signature | HMAC-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
| Plan | Max Webhooks |
|---|---|
| Free | 1 |
| Starter | 2 |
| Pro / Full Stack | 5 |
Payload shape
{
"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
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);
});
/api/webhooks
Register a webhook endpoint
▾
Headers
Authorization: Bearer <token>
Content-Type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
url | string | required | Your HTTPS endpoint URL. |
events | array | required | Event types to subscribe to. Use ["*"] for all. |
description | string | optional | Label for your own reference. |
{
"url": "https://myapp.com/webhook/klairo",
"events": [
"automation.run.completed",
"contact.created",
"chat.message.created"
],
"description": "Production webhook receiver"
}
{
"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"
}
secret is shown only once. Store it immediately in your environment variables — it cannot be retrieved again.| Code | Meaning |
|---|---|
| 201 | Webhook registered. |
| 400 | Invalid URL or events list. |
| 401 | Unauthorized. |
/api/webhooks
List registered webhooks
▾
/api/webhooks/:id
Remove a webhook
▾
/api/webhooks?action=test
Send a test delivery
▾
/api/webhooks?action=deliveries&id=:id
Delivery history (last 50)
▾
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.
/api/analytics
Get usage analytics
▾
Headers
Authorization: Bearer <token>
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
period | string | optional | day | week | month. Default: month. |
from | string | optional | ISO 8601 start date e.g. 2026-03-01. |
to | string | optional | ISO 8601 end date (inclusive). |
curl https://api.klairoai.com/v1/analytics?period=month&from=2026-03-01 \
-H "Authorization: Bearer <token>"
{
"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
}
}
| Code | Meaning |
|---|---|
| 200 | Analytics data returned. |
| 400 | Invalid date range or period. |
| 401 | Unauthorized. |
| 403 | Analytics not available on your plan. |
Current User
Retrieve profile and plan information for the authenticated user. Useful for verifying tokens and checking plan limits in your integration.
/api/users/me
Get current user info
▾
Headers
Authorization: Bearer <token>
curl https://api.klairoai.com/v1/users/me \
-H "Authorization: Bearer <token>"
{
"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"
}
| Code | Meaning |
|---|---|
| 200 | User profile returned. |
| 401 | Invalid or expired token. |
Error Codes
All errors follow a consistent JSON shape. The code field is a machine-readable string
you can use to handle errors programmatically.
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Slow down and retry after 1 minute.",
"status": 429,
"retry_after": 60
}
}
| HTTP Status | Code | Description |
|---|---|---|
| 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. |
429 errors, wait the number of seconds in the Retry-After header before retrying. For 5xx errors, use exponential backoff starting at 1 second.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.
| Plan | API requests / minute | Chat messages / day | Automations max |
|---|---|---|---|
| Starter | 60 | 500 | 10 |
| Growth | 300 | 5,000 | 50 |
| Enterprise | Custom | Unlimited | Unlimited |
Rate limit headers
Every response includes these headers so you can track consumption:
| Header | Description |
|---|---|
X-RateLimit-Limit | Max requests allowed in the current window. |
X-RateLimit-Remaining | Requests remaining in the current window. |
X-RateLimit-Reset | Unix timestamp when the window resets. |
Retry-After | Seconds to wait before retrying (only on 429). |
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.
asyncio support. Pydantic models for all request/response types.Using the API today — Node.js example
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
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"])