Developers
Abe REST API
Read and update contacts, send messages on any connected channel, manage conversations and receive real-time events. The Abe apps use this same API.
Overview
Base URL: https://www.theabeai.com/api/v1. Requests and responses use JSON. Contact IDs are numbers; everything else uses UUIDs. Timestamps are ISO 8601 in UTC.
List endpoints accept page and limit. Message history uses a cursor: pass the nextCursor from a response as before to load older messages.
Authentication
Create an API key in Settings → Integrations → API keys. A key belongs to one workspace and has owner-level access, except managing members and connecting new channels. The full key is shown once; store it securely and never put it in browser or mobile app code.
curl https://www.theabeai.com/api/v1/contacts?limit=20 \ -H "Authorization: Bearer abe_your_key"
Errors and limits
Errors return an HTTP status and a body with a stable code, a readable message and, often, a more specific reason.
HTTP/1.1 400 Bad Request
{
"error": {
"code": "bad_request",
"message": "Some fields are invalid.",
"reason": "validation",
"details": [{ "path": "email", "message": "Invalid email address" }]
}
}Common statuses: 400 invalid input, 401 missing or invalid key, 403 not allowed, 404 not found, 409 conflict, 422 the action isn’t possible right now (for example a closed WhatsApp window), 429 too many requests (retry with backoff) and 5xx temporary errors (retry).
Contacts
| GET | /contacts | Search and list. Query: q, sort, page, limit (max 100). |
| POST | /contacts | Create a contact. |
| GET | /contacts/{id} | A contact with channels, tags, fields and assignee. |
| PATCH | /contacts/{id} | Update name, email, phone, country, language or custom fields. |
| DELETE | /contacts/{id} | Delete a contact with its messages and files. |
| POST | /contacts/{id}/tags | Add and remove tags: { "add": [tagId], "remove": [tagId] }. |
| POST | /contacts/{id}/lifecycle | Set the lifecycle stage: { "stageId": "…" } or null. |
| POST | /contacts/merge | Merge two contacts. |
curl -X POST https://www.theabeai.com/api/v1/contacts \
-H "Authorization: Bearer abe_your_key" -H "Content-Type: application/json" \
-d '{
"firstName": "Aisha",
"lastName": "Rahman",
"phone": "+6591234567",
"email": "aisha@example.com",
"customFields": { "booking_date": "2026-10-04" },
"tagIds": ["2f7c…"]
}'Messages and conversations
| GET | /contacts/{id}/messages | A page of message history (oldest first) and a nextCursor for older messages. Query: before, limit. |
| POST | /contacts/{id}/messages | Send a message on a connected channel. |
| POST | /contacts/{id}/comments | Add an internal comment (never sent to the contact). |
| POST | /contacts/{id}/assign | Assign: { "userId": "…" }, { "agentId": "…" } or both null to unassign. |
| POST | /contacts/{id}/open | Open a conversation. |
| POST | /contacts/{id}/close | Close it, optionally with categoryId and summary. |
| POST | /contacts/{id}/snooze | Snooze until a time: { "until": "2026-10-01T09:00:00Z" }. |
| GET | /contacts/{id}/conversations | Past and current conversations with response metrics. |
| GET | /messages/{id} | One message, including its delivery status. |
Messages go out on the channel you pass as channelId, or on the contact’s last used channel. On WhatsApp, free-form messages are only possible within 24 hours of the contact’s last message; outside that window send an approved template.
# Text
curl -X POST https://www.theabeai.com/api/v1/contacts/1042/messages \
-H "Authorization: Bearer abe_your_key" -H "Content-Type: application/json" \
-d '{ "type": "text", "text": "Hi Aisha, your session is confirmed for Saturday 10am." }'
# WhatsApp template with body variables
curl -X POST https://www.theabeai.com/api/v1/contacts/1042/messages \
-H "Authorization: Bearer abe_your_key" -H "Content-Type: application/json" \
-d '{
"type": "template",
"template": { "name": "booking_reminder", "language": "en", "variables": { "body": ["Aisha", "Saturday 10am"] } }
}'Other types: image, video, audio, file (with a fileId), location, contact and interactive (reply buttons, lists or a link button where the channel supports them). Text may use variables such as $contact.firstname.
On email channels, messages continue the contact’s last email thread (same subject, threaded headers). Pass subject to start a new thread instead. SMS, LINE, Viber and email have no messaging window.
Files
Upload in three steps, then send the file or attach it to a comment by its ID.
| POST | /files/uploads | Reserve an upload: name, mimeType, size. Returns fileId and uploadUrl. |
| POST | /files/{id}/complete | Confirm the upload after sending the bytes. |
| GET | /files | Files in the workspace library. |
# 2. Send the bytes to the uploadUrl you received curl -X PUT "$UPLOAD_URL" -H "Content-Type: application/pdf" --data-binary @price-list.pdf
Workspace data
| GET | /workspace | Workspace settings with members, teams, channels, tags, lifecycle stages, contact fields and closing categories. |
| GET | /tags | Tags. Also POST to create one. |
| GET | /lifecycle-stages | Lifecycle stages in order. |
| GET | /contact-fields | Standard and custom contact fields. |
| GET | /segments | Saved contact segments. |
| GET | /channels | Connected channels and their status. |
| GET | /growth-widgets | Website buttons, chat links and QR codes. /growth-widget-stats counts the conversations each one started. |
Workflows and broadcasts
| GET | /workflows | Workflows with their status and trigger. |
| GET | /contacts/{id}/workflows | Workflows currently running for a contact. |
| GET | /broadcasts | Broadcasts with delivery, read and reply counts. |
| POST | /broadcasts/{id}/send | Send or schedule a broadcast (scheduleAt). |
To start a workflow from your own system, give it an Incoming webhook trigger and POST to the URL shown in the workflow builder.
Webhooks
Add an endpoint in Settings → Integrations → Webhooks and choose events. Abe sends a signed POST for each event and retries failed deliveries with increasing delays for about three hours. Respond with any 2xx status within 5 seconds.
Events: message.received, message.sent, conversation.opened, conversation.closed, contact.created, contact.updated, contact.assigned, contact.tags_updated, contact.lifecycle_updated, comment.created.
POST /your-endpoint
X-Abe-Event: message.received
X-Abe-Delivery: 5d0e…
X-Abe-Signature: t=1790000000,v1=6b1f…
{
"id": "5d0e…",
"type": "message.received",
"workspaceId": "…",
"createdAt": "2026-09-25T08:15:02.114Z",
"data": { "message_id": 88121, "contact_id": 1042, "channel_id": "…" }
}Verify every request: compute an HMAC-SHA256 of {t}.{raw body} with your endpoint’s signing secret and compare it with v1. Reject requests older than five minutes.
import crypto from "node:crypto";
export function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
return fresh && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}AI assistants (MCP)
Abe runs a Model Context Protocol server, so AI assistants such as Claude, ChatGPT and Cursor can work in a workspace: search contacts, read conversations, send messages and WhatsApp templates, add comments, assign, tag, set lifecycle stages and close conversations. Connect with an API key as the Bearer token; the assistant can do whatever the key can.
# Claude Code
claude mcp add --transport http abe https://www.theabeai.com/api/v1/mcp \
--header "Authorization: Bearer abe_your_key"
# Other clients (mcp.json)
{
"mcpServers": {
"abe": {
"type": "http",
"url": "https://www.theabeai.com/api/v1/mcp",
"headers": { "Authorization": "Bearer abe_your_key" }
}
}
}Tools: get_workspace, search_contacts, get_contact, create_contact, update_contact, list_conversations, get_messages, send_message, list_templates, send_template, add_comment, assign_conversation, open_conversation, close_conversation, update_tags and set_lifecycle_stage.
Custom channels
A custom channel connects any messaging service that Abe doesn’t support directly, through a small integration server of your own. Create one in Settings → Channels → Add channel → Custom channel. You get a channel ID, an incoming webhook URL, an API token and a signing secret. The format is compatible with respond.io’s Custom Channel, so an existing integration only needs the new URL and token.
Choose the contact ID type when you create the channel: a custom ID (letters, digits and _ = + / @ . : -, up to 100 characters) or a phone number in international format. With phone numbers your team can also start conversations with existing contacts.
Receiving messages
Post incoming messages, message_echo events (messages sent from another app, shown as sent by your team) and message_status updates to the channel’s incoming webhook URL. Authenticate with Authorization: Bearer <API token>, or sign the body with X-Abe-Signature exactly like Abe’s webhooks above.
POST https://www.theabeai.com/api/webhooks/custom/{channel}
Authorization: Bearer <API token>
Content-Type: application/json
{
"contactId": "+6591234567",
"contact": { "firstName": "Mei", "lastName": "Tan", "email": "mei@example.com", "language": "en" },
"events": [
{ "type": "message", "mId": "m_981", "timestamp": 1790300000000,
"message": { "type": "text", "text": "Hi! Do you open on Sundays?" } },
{ "type": "message", "mId": "m_982", "timestamp": 1790300004000,
"message": { "type": "attachment",
"attachment": { "type": "image", "url": "https://files.example.com/p/123.jpg", "mimeType": "image/jpeg" } } }
]
}
→ 200 { "ok": true, "accepted": 2 }Message types: text (up to 7,000 characters), attachment (image, video, audio or file at a public HTTPS URL, which Abe copies into its own storage), location (latitude, longitude, address) and quick_reply. Send up to 100 events per request and 20 requests per second. Abe answers 400 with the exact problem when the body is invalid, 401 for a wrong token and 429 above the rate limit. Events with an mId Abe has already seen are ignored, so retries are safe.
Sending messages
For every reply, Abe calls your outgoing webhook URL + /message with the same bearer token and a signature. Respond with your service’s message ID; Abe retries network errors, 408, 429 and 5xx responses, and marks the message failed with your error message for other 4xx responses.
POST https://your-server.example.com/message
Authorization: Bearer <API token>
X-Abe-Signature: t=1790300100,v1=…
Idempotency-Key: abe-4821
{
"channelId": "cc_PWw0Tuq7c6vKma94",
"contactId": "+6591234567",
"messageId": "4821",
"message": { "type": "text", "text": "Yes, 10am to 6pm." }
}
→ 200 { "mId": "provider-msg-77" }Report delivery with a message_status event whose mId is the ID you returned (or pass Abe’s messageId if you had none): { "type": "message_status", "mId": "provider-msg-77", "status": { "value": "delivered" } }. Values: sent, delivered, read and failed (with a message explaining why).
Questions or need another endpoint? Email mail@solarai.asia. See also our terms.