Getting started
Create an API key, verify it, create a contact and send a WhatsApp message — the RaabtaHQ REST API in four calls, with curl, Node and Python samples.
Create an API key
Keys are created in the dashboard under Settings → API keys by an account admin or owner. Give the key a name that says what will use it, tick the scopes it needs and nothing more, and optionally an expiry, an IP allowlist and a lower rate limit.
The full key is shown once. It starts with raabta_hq_live_ followed by 43 random characters, and the server stores only a hash of it — there is no way to see it again. Put it in your environment as RAABTA_API_KEY; every sample on this site reads it from there.
Lost a key?
Verify it works
GET /me needs a valid key and no scope, so it is the first call to make: it exercises the whole path — bearer parsing, the hash lookup, liveness, the rate limiter, the envelope — and tells you which account the key is bound to and what it may do.
curl "https://your-crm.example.com/api/v1/me" \
-H "Authorization: Bearer $RAABTA_API_KEY"{
"data": {
"account": {
"id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
"name": "Acme Clinic"
},
"key": {
"id": "7c1e2d3f-4a5b-4c6d-8e9f-0a1b2c3d4e5f",
"name": "Zapier automation",
"scopes": [
"contacts:write",
"messages:send"
],
"effective_scopes": [
"contacts:read",
"contacts:write",
"messages:send",
"templates:read"
],
"expires_at": "2026-12-01T00:00:00.000Z",
"rate_limit_per_minute": 60
}
}
}effective_scopes is the granted scopes plus the ones they imply — a key with contacts:write can also read contacts. The authentication guide has the full table.
Create a contact
A contact needs at least one of a phone, a name or an email. Phone numbers are E.164 and deduplicated by digits, so creating a contact whose number already exists returns 409 conflict with the existing id in details rather than a second record.
curl -X POST "https://your-crm.example.com/api/v1/contacts" \
-H "Authorization: Bearer $RAABTA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c2a9e-3b4d-4c5e-8f7a-9b0c1d2e3f4a" \
-d '{
"phone": "+971501234567",
"name": "Ayesha Khan",
"email": "ayesha@example.com",
"company": "Khan Trading LLC",
"tag_ids": [
"1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f"
],
"custom_fields": {
"6a7b8c9d-0e1f-4a2b-8c3d-4e5f6a7b8c9d": "Instagram ad"
}
}'{
"data": {
"id": "9d7e4c11-5a2b-4f7c-8e3d-2a1b0c9d8e7f",
"name": "Ayesha Khan",
"phone": "+971501234567",
"email": "ayesha@example.com",
"company": "Khan Trading LLC",
"avatar_url": null,
"tags": [
{
"id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"name": "VIP",
"color": "#10b981"
}
],
"custom_fields": [
{
"field_id": "6a7b8c9d-0e1f-4a2b-8c3d-4e5f6a7b8c9d",
"name": "Source",
"value": "Instagram ad"
}
],
"created_at": "2026-09-01T08:15:00.000Z",
"updated_at": "2026-09-02T10:00:00.000Z"
}
}Every create endpoint accepts an Idempotency-Key header. Send one and a retried request returns the first result instead of creating twice — see Idempotency.
Send a message
POST /messages takes a to target that is either an existing conversation_id or a phone on WhatsApp — in which case the contact and the thread are found or created for you.
curl -X POST "https://your-crm.example.com/api/v1/messages" \
-H "Authorization: Bearer $RAABTA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c2a9e-3b4d-4c5e-8f7a-9b0c1d2e3f4a" \
-d '{
"type": "text",
"to": {
"phone": "+971501234567",
"channel": "whatsapp"
},
"text": "Your appointment is confirmed for Saturday at 11:00."
}'{
"data": {
"id": "0c1d2e3f-4a5b-4c6d-8e7f-8a9b0c1d2e3f",
"conversation_id": "4e5f6a7b-8c9d-4e0f-a1b2-c3d4e5f6a7b8",
"direction": "outbound",
"sender_type": "bot",
"type": "text",
"text": "Your appointment is confirmed for Saturday at 11:00.",
"media_url": null,
"template_name": null,
"status": "sent",
"channel_message_id": "wamid.HBgLOTcxNTAxMjM0NTY3FQIAERgSN0Y4MjA1QzYwRjkzMDAyMzRCAA==",
"reply_to_message_id": null,
"created_at": "2026-09-02T10:00:00.000Z"
}
}The 24-hour window
422 unprocessable and reason: outside_window; send an approved template instead (type: "template").Where next
- The API reference — every endpoint with its parameters, a worked example and the errors it can return.
- Errors and rate limits — what to branch on and when to back off.
- Pagination — every list endpoint uses the same cursor.
- Webhooks — get events pushed to you instead of polling.
- The OpenAPI 3.1 document — import it into Postman, Insomnia or a client generator.
Most integrations start with these three:
- GET
/api/v1/contacts— List contacts - GET
/api/v1/conversations— List conversations - POST
/api/v1/deals— Create a deal
Or browse by resource: contacts, conversations, messages, broadcasts, pipelines & deals.