Send one message to one or more recipients
One call, one body, one channel, many recipients — and one message object back per recipient. A message is one row of delivery: one person, one status. Sending to three numbers returns three objects. Recipients must be in E.164 form, with the +. A local number is refused rather than guessed: guessing the wrong country sends a stranger a message and bills you for it.
Try it — POST /messages
Kept for this tab only — it disappears when you close it, and it is never sent anywhere except as the Authorization header on the call below.
Authorization
bearerAuth messages:writeAuthorization: Bearer sk_live_.... Keys in the query string or the
request body are refused — a URL is logged by every proxy it passes,
and that is how customer keys leak.
A key carries scopes. A call outside them answers 403 with
insufficient_scope and names the scope it wanted.
In: header
Scope: messages:write
Header Parameters
Any unique string, one per logical request. Retrying with the same key
returns the first answer instead of doing the work twice, and answers
with Idempotent-Replay: true.
length <= 255Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
One body, one channel, many recipients. Fields that do not belong to the channel you picked are refused by name rather than ignored: a caller on the wrong channel should find out on the first try, not after the message went out without its subject.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST https://app.sendkuy.com/api/v1/messages \ -H "Authorization: Bearer sk_live_YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "channel": "whatsapp", "to": [ "+6281234567890" ], "body": "Your order is on its way."}'{ "data": [ { "object": "message", "id": "msg_9cBe3A1H-SLhW5fONWZ32wb-IIio5Ts3", "channel": "email", "status": "queued", "to": "+6281234567890", "body": "string", "subject": "string", "contact_id": "con_9cBe3A1H-SLhW5fONWZ32wb-IIio5Ts3", "campaign_id": "string", "scheduled_at": "2019-08-24T14:15:22Z", "sent_at": "2019-08-24T14:15:22Z", "error": "string", "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z" } ]}List messages you have sent GET
Newest first, cursor-paginated. Filters narrow the list; they do not change the shape of what comes back.
Send up to 500 independent messages in one call POST
Not a repeat of POST /messages. Each element carries its own channel, recipient and body, and each one is answered on its own row: index, the id that was created, and error when that element failed. One mistyped number does not throw away the 499 that were fine. The rows carry ids, not message objects. Read a message back with GET /messages/{id} if you need its full state. Status is 200, not 201, because a batch that failed entirely still answers row by row.