One REST API for everything WhatsApp — send messages and templates, verify OTPs, manage contacts and labels, read conversations, trigger chatbots and drip sequences, and read commerce catalogs. Built on the official WhatsApp Business Platform.
https://api.wamark.in/v1 · Every request is JSON over HTTPS and authenticated with your API key.The WaMark API lets your app or CRM drive your WhatsApp Business number programmatically. Create an API key in Settings → Developer, choose the scopes you need, and start calling. Every send is metered against your plan and billed at the Meta rate — no hidden markup.
Send your key on every request as a Bearer token (or the x-api-key header):
# Bearer header (recommended)
Authorization: Bearer wam_xxxxxxxxxxxxxxxxxxxxxxxx
# …or
x-api-key: wam_xxxxxxxxxxxxxxxxxxxxxxxx
Keys look like wam_… and are shown once at creation. Each key is scoped to a single workspace; all data access is tenant-isolated at the database level.
A key only reaches the endpoints its scopes allow — a call to an out-of-scope endpoint returns 403. Grant the least you need.
| Scope | Grants |
|---|---|
messages | Send messages, bulk send, upload media, read message status |
otp | Send & verify WhatsApp OTP codes |
contacts | Read, create, update, delete contacts & labels |
templates | List your approved message templates |
conversations | Read chat history, assign chats to agents |
chatbots | List & trigger chatbot flows |
sequences | Manage drip sequences & enrol contacts |
catalog | Read commerce catalogs & products |
account | Read account info, plan & quota |
Each key is limited per IP: 120 requests/min by default, with tighter caps on sensitive endpoints (messages 60/min, bulk 10/min, OTP 10/min). Exceeding a limit returns 429. Every message send also checks your plan quota and debits your per-number wallet at the Meta rate.
Errors use standard HTTP status codes with a JSON body { "message": "…", "statusCode": 4xx }.
| Code | Meaning |
|---|---|
400 | Bad request — a required field is missing or malformed |
401 | Missing or invalid API key |
403 | Your key is missing the required scope |
404 | The resource (message, contact, conversation…) was not found |
429 | Rate limit exceeded — slow down and retry |
error field. Free text only delivers inside the 24-hour customer-service window; outside it, send an approved template.Send a single text or media message. Media can be a public mediaUrl or a mediaId from /v1/media.
Request — text
curl -X POST https://api.wamark.in/v1/messages \
-H "Authorization: Bearer wam_xxx" -H "Content-Type: application/json" \
-d '{"to":"15551234567","body":"Hello from our app 👋"}'
Request — document
-d '{"to":"15551234567","type":"document","mediaUrl":"https://example.com/invoice.pdf","filename":"invoice.pdf","caption":"Your invoice 🧾"}'Response
{ "id": "2567b319-…", "wamid": "wamid.HBg…", "status": "sent", "error": null }| Field | Notes |
|---|---|
to required | Recipient in international format (national numbers are auto-prefixed with the workspace country code) |
body | Text (required for a text message) |
type | document / image / video / audio for media |
mediaUrl / mediaId | Public URL Meta can fetch, or an uploaded media id |
filename, caption | Optional, for media messages |
Fan one send out to up to 200 recipients per call, with per-recipient variables. Two modes.
Sends one approved template per recipient; the template’s buttons ride along. variables fill the body {{vars}}; buttonUrl injects a per-recipient value into a dynamic URL button.
-d '{
"template": "order_update", "language": "en",
"recipients": [
{"to":"15551230001","variables":{"name":"Ravi","1":"BK-1029"},"buttonUrl":"1029"},
{"to":"15551230002","variables":{"name":"Sana","1":"BK-1030"},"buttonUrl":"1030"}
], "fallback": ""
}'For finer control (multiple buttons, or non-URL subtypes), send a buttons array per recipient instead of buttonUrl. index is the button’s 0-based position in the approved template, subtype is url, quick_reply or copy_code, and value is the per-recipient value.
-d '{
"template": "due_date_notification", "language": "en",
"recipients": [
{ "to":"9XXXXXXXXX",
"variables": {"1":"1234","2":"value1","3":"value1"},
"buttons": [ {"index":0,"subtype":"url","value":"1029"} ] }
]
}'Reply buttons defined at send time. Delivers only inside the 24-hour window; cold recipients return status:"skipped".
-d '{
"type": "buttons", "body": "Your order is ready. Collect today?",
"buttons": [ {"label":"Yes"}, {"label":"Reschedule"} ],
"recipients": [ {"to":"15551230001"}, {"to":"15551230002"} ]
}'Response
{ "total":2, "sent":2, "skipped":0, "failed":0,
"results":[ {"to":"…","status":"sent","id":"…","wamid":"…"} ] }Host a file and get a public mediaUrl to pass to /v1/messages. Allowed: PDF, JPEG/PNG/WebP/GIF, MP4 (≤16 MB). File contents are verified against the declared type.
curl -X POST https://api.wamark.in/v1/media \
-H "Authorization: Bearer wam_xxx" \
-F "file=@invoice.pdf"
→ { "mediaUrl": "https://api.wamark.in/uploads/…/x.pdf", "type": "document" }
Look up delivery status by the id we return on send, or the WhatsApp wamid. Reflects the latest Meta callback.
curl https://api.wamark.in/v1/messages/MESSAGE_ID/status -H "Authorization: Bearer wam_xxx"
→ { "status": "delivered", "type":"text", "to":"…", "sentAt":"…" }
Status lifecycle: accepted → sent → delivered → read (or failed).
WaMark generates, stores and expires the code for you.
curl -X POST https://api.wamark.in/v1/otp/send -d '{"to":"15551234567","brand":"WaMark","codeLength":6}'
curl -X POST https://api.wamark.in/v1/otp/verify -d '{"to":"15551234567","code":"123456"}'
→ { "verified": true }
Full contact lifecycle. GET /v1/contacts accepts search, stage, company, country, source, vip filters.
curl -X POST https://api.wamark.in/v1/contacts \
-d '{"fullName":"Jane Doe","phone":"15551234567","email":"jane@example.com"}'
curl -X PATCH https://api.wamark.in/v1/contacts/CONTACT_ID \
-d '{"attributes":{"plan":"pro"},"lifecycleStage":"customer"}'
Create and list labels, then assign or remove them on a contact. Assigning merges with the contact’s existing labels.
curl -X POST https://api.wamark.in/v1/labels -d '{"name":"VIP","color":"#22c55e"}'
curl -X POST https://api.wamark.in/v1/contacts/CONTACT_ID/labels -d '{"labelIds":["LABEL_ID"]}'
List conversations, read a thread’s history (paged — never marks the agent’s unread badge), and assign a chat to a team member (userId: null to unassign).
curl "https://api.wamark.in/v1/conversations/CONVERSATION_ID/messages?limit=50" -H "Authorization: Bearer wam_xxx"
curl -X POST https://api.wamark.in/v1/conversations/CONVERSATION_ID/assign -d '{"userId":"USER_ID"}'
List your message templates (optionally ?status=approved) so you know exactly what you can send.
curl "https://api.wamark.in/v1/templates?status=approved" -H "Authorization: Bearer wam_xxx"List your chatbots and run one on demand for a phone number — the flow executes from its start. A cold contact needs the bot’s first step to be a template.
curl -X POST https://api.wamark.in/v1/chatbots/CHATBOT_ID/trigger -d '{"to":"15551234567"}'A scheduled, multi-step message journey. Each step waits afterMinutes, then sends a template (works any time) or free text (in-window). Opted-out contacts are dropped automatically.
curl -X POST https://api.wamark.in/v1/sequences -d '{
"name":"Welcome", "status":"active",
"steps":[
{"afterMinutes":0, "type":"template","template":"welcome","language":"en"},
{"afterMinutes":1440,"type":"text","body":"Any questions? 😊"}
] }'
curl -X POST https://api.wamark.in/v1/sequences/SEQ_ID/enroll -d '{"to":"15551234567"}'
Read your connected commerce catalogs and their products (paged via ?after=).
curl https://api.wamark.in/v1/catalogs -H "Authorization: Bearer wam_xxx"Your workspace’s plan plus messaging and AI quota (used / included / remaining).
curl https://api.wamark.in/v1/me -H "Authorization: Bearer wam_xxx"The full machine-readable reference (OpenAPI 3.0, no key required) — import it into Postman, Insomnia or any codegen tool.
https://api.wamark.in/v1/openapi.json
A one-call, no-header endpoint for legacy CRM “SMS gateway” screens — pass your token and message as request parameters. Ideal when a system can only send a single URL with query params.
curl "https://api.wamark.in/gateway/send?token=YOUR_TOKEN&to=15551234567&text=Hello"
/v1 API above with a wam_ key.Questions? Talk to us · Manage keys in Settings → Developer.