Quickstart
-
Create a key
Section titled “Create a key”In the dashboard, open Settings → API Keys and choose Create API key.
Name it after the system that will use it, so you know what breaks if you ever revoke it. Then tick the permissions it needs. For this quickstart:
- Read account (
account:read) - Send messages (
messages:send)
Grant the least it needs. You can add scopes later without replacing the key.
The key is shown once and never again. Nothing anywhere stores it, only a hash of it, so copy it now.
- Read account (
-
Prove the key works
Section titled “Prove the key works”Before sending anything, make the call that cannot go wrong.
Terminal window curl https://k-message.kerneltics.com/v1/me \-H "Authorization: Bearer km_live_YOUR_KEY"const res = await fetch('https://k-message.kerneltics.com/v1/me', {headers: { Authorization: `Bearer ${process.env.KM_API_KEY}` },})console.log(await res.json())$ch = curl_init('https://k-message.kerneltics.com/v1/me');curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true,CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('KM_API_KEY')],]);echo curl_exec($ch);import os, requestsres = requests.get("https://k-message.kerneltics.com/v1/me",headers={"Authorization": f"Bearer {os.environ['KM_API_KEY']}"},)print(res.json())Response {"organization": { "id": "8f3a...", "name": "Zaiti Auto Parts", "slug": "zaiti" },"api_key": {"name": "Orders service","prefix": "km_live_a1b2c3d4","scopes": ["account:read", "messages:send"],"rate_limit_per_min": 600},"whatsapp_accounts": [{"name": "Main","display_phone_number": "+966 51 021 5213","is_default_outgoing": true,"quality_rating": "GREEN"}]}This call reaches the database, so a
200means the key is real, active and scoped correctly. It cannot send anything or change anything, which is why it is the right first call: when an integration is misconfigured, this is what says so, before a failed send has confused matters.If it fails, the body names the reason. See Errors.
-
Send a message
Section titled “Send a message”Whether you can send free text depends on the 24-hour window. If the person has messaged your business in the last 24 hours, a text message goes through:
Terminal window curl https://k-message.kerneltics.com/v1/messages \-H "Authorization: Bearer km_live_YOUR_KEY" \-H "Content-Type: application/json" \-H "Idempotency-Key: order-1001-shipped" \-d '{"to": "+966500000000","type": "text","text": { "body": "Your order has shipped." }}'const res = await fetch('https://k-message.kerneltics.com/v1/messages', {method: 'POST',headers: {Authorization: `Bearer ${process.env.KM_API_KEY}`,'Content-Type': 'application/json',// Derived from the thing that happened, so a retry reuses it.'Idempotency-Key': `order-${order.id}-shipped`,},body: JSON.stringify({to: '+966500000000',type: 'text',text: { body: 'Your order has shipped.' },}),})$ch = curl_init('https://k-message.kerneltics.com/v1/messages');curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true,CURLOPT_POST => true,CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('KM_API_KEY'),'Content-Type: application/json','Idempotency-Key: order-1001-shipped',],CURLOPT_POSTFIELDS => json_encode(['to' => '+966500000000','type' => 'text','text' => ['body' => 'Your order has shipped.'],]),]);echo curl_exec($ch);res = requests.post("https://k-message.kerneltics.com/v1/messages",headers={"Authorization": f"Bearer {os.environ['KM_API_KEY']}","Idempotency-Key": f"order-{order_id}-shipped",},json={"to": "+966500000000","type": "text","text": {"body": "Your order has shipped."},},)Response 201 {"id": "6f1c2d3e-4a5b-4c6d-8e9f-0a1b2c3d4e5f","contact_id": "3f2a...","to": "+966500000000","from": "Main","type": "text","direction": "outgoing","status": "pending","content": "Your order has shipped.","created_at": "2026-08-20T09:15:00Z"}If the person has not messaged you in the last 24 hours, this returns a failure and you need an approved template instead. See Send a template message.
-
Learn what happened
Section titled “Learn what happened”Two ways, and you want the second one in production.
Read the message back, using the
idfrom the response:Terminal window curl https://k-message.kerneltics.com/v1/messages/6f1c2d3e-... \-H "Authorization: Bearer km_live_YOUR_KEY"The
statusmovespending→sent→delivered→read, or lands onfailedwith anerror_messageexplaining why.Or subscribe to webhooks, so the outcome arrives at your server without polling. Create one in Settings → Webhooks, tick
message.delivered,message.readandmessage.failed, and read Receive messages.
Where to go next
Section titled “Where to go next”- Send a template message — required outside the 24-hour window, which in practice means most notifications.
- Receive messages — get replies and delivery receipts pushed to you.
- Errors — every code, what causes it, and what to do.
- Going live — the checklist before you point production at this.