ZeniaOne API
919999999999 and YOUR_API_KEY โ swap in your own to go live.Base URL
Every endpoint lives under a single versioned base URL. Requests and responses are JSON.
https://zeniaone.com/api/v1The complete, always-current, interactive reference (every endpoint and field) is published as OpenAPI at zeniaone.com/api/docs.
Authentication
Create an API key in your dashboard under Settings โ API & Webhooks. Send it on every request in the X-Api-Key header. The key identifies your workspace, so you never send a workspace id.
X-Api-Key: YOUR_API_KEY
Content-Type: application/jsonEach key is limited to the scopes you grant it โ request only what you need:
| Scope | Grants |
|---|---|
| messages:send | Send messages & templates |
| messages:read | Read message status & history |
| contacts:read | Read contacts |
| contacts:write | Create / update contacts |
| templates:read | Read templates |
| templates:write | Create / submit / manage templates |
| campaigns:read | Read campaigns |
| campaigns:write | Launch / schedule / manage campaigns |
| media:write | Upload media |
| webhooks:manage | Manage outbound webhooks |
Send a message
POST /messages sends to a recipient. Give the recipient in to (their number in international format, digits only, no +), or send into an existing chat with conversationId. Scope: messages:send.
Text
curl -X POST https://zeniaone.com/api/v1/messages \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "text",
"to": "919999999999",
"body": "Hello from ZeniaOne ๐"
}'A successful call returns the created message:
{
"id": "cmt4rtf8300blpi010axy500m",
"waMessageId": "wamid.HBgMOTE5OTk5OTk5OTk5...",
"type": "TEXT",
"status": "SENT"
}Template
Outside the 24-hour service window you must send an approved template. In templateId pass the template name exactly as it appears in WhatsApp Manager (its internal id also works), and fill its {{1}} variables in order. The template used is the approved copy on the number you send from; add an optional language if the same name exists in more than one language.
curl -X POST https://zeniaone.com/api/v1/messages \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "template",
"to": "919999999999",
"templateId": "welcome_message_website",
"variables": ["Ravi", "ORD-1234"]
}'Media (image, video, document, audio)
curl -X POST https://zeniaone.com/api/v1/messages \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "image",
"to": "919999999999",
"link": "https://example.com/receipt.jpg",
"caption": "Your receipt"
}'Optional fields: phoneNumberId (which of your WhatsApp numbers to send from; defaults to your primary), contextMessageId (reply to a message), and filename for documents. Interactive buttons, lists, location and reactions are also supported โ see the full reference.
Check delivery status
GET /messages/{waMessageId}returns a message's current status. Scope: messages:read.
curl https://zeniaone.com/api/v1/messages/wamid.HBgMOTE5OTk5... \
-H "X-Api-Key: YOUR_API_KEY"Status moves through SENT โ DELIVERED โ READ, or FAILED with a reason. Prefer webhooks (below) for real-time updates instead of polling.
Contacts
Create or update a contact. Upserts on the WhatsApp number, so calling it twice for the same number updates the record. Scope: contacts:write (read: contacts:read).
curl -X POST https://zeniaone.com/api/v1/contacts \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"waId": "919999999999",
"name": "Ravi Kumar",
"email": "ravi@example.com"
}'Templates
List your message templates and their approval status. Scope: templates:read.
curl "https://zeniaone.com/api/v1/templates?status=APPROVED" \
-H "X-Api-Key: YOUR_API_KEY"Webhooks
Register a webhook URL under Settings โ API & Webhooks to receive events as JSON POSTs: inbound messages from customers and delivery-status updates (sent, delivered, read, failed). This is the recommended way to build real-time integrations.
{
"event": "message.received",
"workspaceId": "ws_...",
"conversation": { "id": "...", "contact": { "waId": "919999999999", "name": "Ravi Kumar" } },
"message": { "type": "text", "body": "Hi, is this available?", "waMessageId": "wamid...." }
}Each delivery is signed so you can verify it came from ZeniaOne. Configure the URL and see the exact payloads in your dashboard.
Rate limits
Each API key has a per-minute rate limit (300 requests/minute by default; configurable per key). Every response includes headers so you can back off gracefully:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 297
X-RateLimit-Reset: 42Errors
Errors return a JSON body with a message and the right HTTP status:
| HTTP | Meaning |
|---|---|
| 400 | Invalid request body or missing a required field |
| 401 | Missing or invalid API key |
| 403 | The key lacks the required scope |
| 404 | Resource not found |
| 429 | Rate limit exceeded โ retry after X-RateLimit-Reset seconds |
A send can succeed (the API returns the message) and still fail at delivery for a WhatsApp policy reason, reported later on the message status. Common ones: 131049 (a per-recipient marketing-frequency cap โ try a different recipient or a utility template), 131047 (re-engagement needed โ send an approved template), and 131026(the number can't receive WhatsApp messages).
Full reference
Browse and try every endpoint interactively in the OpenAPI reference: