Skip to main content

Send a message

POST/messaging/v1/messages

Sends one SMS or WhatsApp message to one number. Ponitor returns the message, already charged and queued. Its status changes as the network reports back.

Request body​

  • #channelstringRequired
    SMS or WHATSAPP.
    Example: SMS
  • #senderstringRequired
    For SMS, your approved Sender ID or Short Code. For WhatsApp, your WhatsApp number (+231770000000, with or without the +).
    Example: ACME
  • #recipientstringRequired
    The phone number, in international format, with or without the +. On WhatsApp, it can also be the ID WhatsApp gives someone who hides their number (LR.1349…), from a received message's sender. Authentication templates can only go to a phone number.
    Example: +231770000000
  • #workspacestringOptional
    The handle of the workspace to send from and charge, such as gbarnga-branch. Leave it out for Main. See Workspaces.
    Example: gbarnga-branch
  • #externalIdstringRequired
    Your own reference, up to 64 characters, unique within your team. If you reuse one, you get the original message back with 200. Nothing is sent or charged again. See Retries and externalId.
    Example: order-42
  • #textstringOptional
    The message's text. For SMS, 2 to 640 characters. For WhatsApp, 2 to 4,096 characters, inside the 24-hour window. See WhatsApp replies.
    Example: Your Acme order 42 is on its way.
  • #image, video, audio, documentobjectOptional
    WhatsApp only, inside the 24-hour window. A file at a link. See WhatsApp replies for the types and sizes each one takes.
    Example: { "url": "https://example.com/r.jpg", "caption": "Receipt" }
    3 child parameters
    • #urlstringRequired
      A public link to the file, up to 2,048 characters. See The file's link below.
    • #captionstringOptional
      Up to 1,024 characters. Not for audio.
    • #filenamestringOptional
      document only. Up to 240 characters, for your records. The customer's WhatsApp doesn't show it.
  • #buttonsobject[]Optional
    WhatsApp only, with text of up to 1,024 characters, inside the 24-hour window. Up to 3 reply buttons. See Buttons, lists and links.
    Example: [{ "id": "yes", "title": "Yes" }]
    2 child parameters
    • #idstringRequired
      Up to 128 characters, different for each button. It comes back in the reply.
    • #titlestringRequired
      The words on the button, up to 20 characters.
  • #listobjectOptional
    WhatsApp only, with text of up to 1,024 characters, inside the 24-hour window. A list of up to 10 rows.
    2 child parameters
    • #buttonstringRequired
      The words on the button that opens the list, up to 20 characters.
    • #itemsobject[]Required
      1 to 10 rows.
      3 child parameters
      • #idstringRequired
        Up to 128 characters, different for each row.
      • #titlestringRequired
        Up to 24 characters.
      • #descriptionstringRequired
        Up to 72 characters.
  • #stickerobjectOptional
    WhatsApp only, inside the 24-hour window. A WebP of exactly 512 by 512 pixels, under 100 KB.
    1 child parameter
    • #urlstringRequired
      A public link to the sticker.
  • #locationobjectOptional
    WhatsApp only, inside the 24-hour window. A pin the customer can open in their maps.
    Example: { "latitude": 6.3005, "longitude": -10.7969, "name": "Office" }
    4 child parameters
    • #latitudenumberRequired
      From -90 to 90.
    • #longitudenumberRequired
      From -180 to 180.
    • #namestringOptional
      Up to 100 characters. The pin shows it.
    • #addressstringOptional
      Up to 200 characters. The pin shows it when there's no name.
  • #contactsobject[]Optional
    WhatsApp only, inside the 24-hour window. Up to 10 contact cards. The customer can call or save each one.
    3 child parameters
    • #namestringRequired
      Up to 100 characters.
    • #phonesstring[]Optional
      Up to 5 numbers.
    • #emailsstring[]Optional
      Up to 5 email addresses.
  • #templateobjectOptional
    WhatsApp only. An approved template by its ID, with its values. See Send a template.
    Example: { "id": "6f1c2a3e-8b4d-4e5f-9a1b-2c3d4e5f6a7b", "body": ["Blama"] }
    3 child parameters
    • #idstringRequired
      The Template ID from WhatsApp › Templates in the app. It must be approved for the number you send from.
    • #bodystring[]Optional
      The values for {{1}}, {{2}} and so on, in order. Up to 20 values of up to 1,024 characters each.
    • #buttonsstring[]Optional
      The values for the buttons' placeholders, in order.
  • #smsFallbackobjectOptional
    WhatsApp only. An SMS to send instead if the number isn't on WhatsApp. See If they're not on WhatsApp.
    Example: { "sender": "ACME", "text": "Your order 42 is ready." }
    2 child parameters
    • #senderstringRequired
      Your approved SMS Sender ID or Short Code.
    • #textstringRequired
      Up to 640 characters. {{firstname}}, {{lastname}} and {{fullname}} are filled in from your saved contact.
  • #contentstring or objectOptionalDeprecated
    The older way to send a message. Text for SMS, or for WhatsApp an object such as { "type": "text", "text": { "body": "…" } }. It still works. Use text, or the field named after the message's type.
    Example: Your Acme order 42 is on its way.
  • #templateId, templateParametersstring, string[]OptionalDeprecated
    The older way to send a WhatsApp template. The Template ID from WhatsApp › Templates, and all its values in one list. It still works. Use template.
    Example: "6f1c2a3e-8b4d-4e5f-9a1b-2c3d4e5f6a7b", ["Blama", "LRD 4,500"]

Send the content in one field only: text, image, video, audio, document, sticker, location, contacts or template, or the older content or templateId. buttons, list or link go with text, one of them at a time. Fields not listed here are refused. See Sending SMS and Sending WhatsApp messages for how each channel works.

Example request​

curl -X POST "https://sandbox-api.ponitor.com/messaging/v1/messages" \
-H "apiKey: $PONITOR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"channel": "SMS",
"sender": "ACME",
"recipient": "+231770000000",
"externalId": "order-42",
"text": "Your Acme order 42 is on its way."
}'

Responses​

Created. The message was accepted, charged and queued. The body is the message.

{
"message": {
"id": "e2c38865-dc0a-4299-baef-c07a9bfa9c33",
"content": "Your Acme order 42 is on its way.",
"text": "Your Acme order 42 is on its way.",
"sender": "ACME",
"status": "QUEUED",
"channel": "SMS",
"direction": "OUTBOUND",
"recipient": "+231770000000",
"messageType": null,
"inServiceWindow": null,
"cost": 0.05,
"conversationId": null,
"failedReason": null,
"externalId": "order-42",
"createdAt": "2026-10-05T09:30:00.112Z",
"updatedAt": "2026-10-05T09:30:00.112Z"
}
}

Send a template​

Set template to an approved template's ID and its values. The ID is the Template ID on the template's page in WhatsApp › Templates.

{
"channel": "WHATSAPP",
"sender": "+231770000000",
"recipient": "+231770123456",
"externalId": "remind-0412",
"template": {
"id": "6f1c2a3e-8b4d-4e5f-9a1b-2c3d4e5f6a7b",
"body": ["Blama", "LRD 4,500", "18 June"],
"buttons": ["loans/0412"]
}
}
FieldTypeMeaning
idstringThe template's ID, from the app. It must be approved for the number you send from.
bodystring[]The values for {{1}}, {{2}} and so on, in order. Up to 20 values of up to 1024 characters each. Leave it out if the template has no placeholders.
buttonsstring[]The values for the buttons' placeholders, in order, such as the end of a link button's address. Leave it out if the buttons have none.

A template belongs to a WhatsApp account. Send it from a number in that account. Each WhatsApp account has its own copy of a template, with its own ID.

The header (text, a photo, a video or a document) is sent as approved. A template with too few or too many values is refused with 400. The message says how many values it takes. The older templateId with templateParameters still works.

If they're not on WhatsApp​

Add smsFallback to a WhatsApp message to send an SMS if the number isn't on WhatsApp. The WhatsApp message goes first. If WhatsApp reports that the number isn't on WhatsApp, Ponitor sends the SMS once from your Sender ID. It's charged as an SMS.

{
"channel": "WHATSAPP",
"sender": "+231770000000",
"recipient": "+231880000000",
"externalId": "ready-0412",
"template": { "id": "6f1c2a3e-8b4d-4e5f-9a1b-2c3d4e5f6a7b", "body": ["Blama"] },
"smsFallback": { "sender": "ACME", "text": "Hi {{firstname|there}}, your order 42 is ready." }
}
FieldWhat it is
senderYour approved SMS Sender ID or Short Code.
textUp to 640 characters. {{firstname}}, {{lastname}} and {{fullname}} are filled in from your saved contact.

To cover contacts with no saved name, add a default after a bar. {{firstname|there}} becomes "there".

The SMS is a separate message with its own ID, status and webhook events. The WhatsApp message's smsFallback shows the SMS's messageId once it's sent. Get the message to read it. The SMS can't go to a WhatsApp user ID, because there's no number to text.

WhatsApp replies​

Inside the 24-hour window, you can reply with text, one file, a sticker, a location or contact cards. Put it in the field named after its type.

FieldHoldsWhat it takes
textThe text2 to 4,096 characters. WhatsApp formatting (*bold*, _italic_, ~strikethrough~) works.
imageurl, caption (optional)JPEG or PNG, up to 5 MB.
videourl, caption (optional)MP4 with H.264 video and AAC audio, up to 16 MB. The caption is sent as a separate text message after the video is delivered, and charged as a reply.
audiourlOGG with the Opus codec arrives as a voice note. MP3, AAC and AMR arrive as an audio file. Up to 16 MB. No caption.
documenturl, filename (optional), caption (optional)PDF, Word (DOC, DOCX), Excel (XLSX) or PowerPoint (PPTX), up to 20 MB. The caption is sent as a separate text message after the document is delivered, and charged as a reply.
stickerurlA WebP of exactly 512 by 512 pixels, under 100 KB, with a clear background. Not animated.
locationlatitude, longitude, name and address (optional)A pin the customer can open in their maps. The pin shows name, or address if there's no name.
contactsA list of cards: name, phones and emails (optional)Up to 10 cards, each with up to 5 phones and 5 emails. The customer can call or save each one.

Each field goes next to channel, sender, recipient and externalId, as in the example request. The older content ({ "type": "image", "image": { "link": "…" } }) still works.

For example, an image with a caption:

"image": {
"url": "https://example.com/receipts/order-42.jpg",
"caption": "Your receipt for order 42"
}

Send text with one of these fields. The customer answers with a tap.

FieldHoldsWhat it takes
buttonsA list of { "id", "title" }Up to 3 reply buttons. Each title up to 20 characters, each id up to 128 and different. text up to 1,024 characters.
listbutton, and items: a list of { "id", "title", "description" }button is the label that opens the list, up to 20 characters. Up to 10 rows. Each row needs a title of up to 24 characters and a description of up to 72. text up to 1,024 characters.
linktitle and urlOne button that opens an https link. title up to 20 characters. text up to 640 characters.
{
"channel": "WHATSAPP",
"sender": "+231770000000",
"recipient": "+231770123456",
"externalId": "slot-0412",
"text": "Pick a delivery slot",
"list": {
"button": "Slots",
"items": [
{ "id": "am", "title": "Morning", "description": "8am to 12pm" },
{ "id": "pm", "title": "Afternoon", "description": "12pm to 5pm" }
]
}
}

When the customer taps a button or picks a row, the message.received webhook includes reply. It has the id you sent, the title, and a row's description. Match on id. It stays the same when you change the words. Outside the 24-hour window, send an approved template with quick-reply buttons.

  • The link must open without signing in. The file is fetched when the message goes out. Keep the link working until the message is DELIVERED.
  • The link must return the file's real Content-Type, such as image/jpeg or application/pdf. A file whose type doesn't match isn't sent.
  • Send one file per message.
  • filename is for your records. The customer's WhatsApp doesn't show it.

A file costs the same as a text reply. If the file can't be fetched, is too large or has an unsupported type, the message ends as FAILED or UNDELIVERED. The reason is in failedReason. See Delivery statuses.

The message object​

Get a message returns the same object.

FieldTypeMeaning
iduuidPonitor's ID for the message.
channelstringSMS or WHATSAPP.
directionstringOUTBOUND for messages you send, INBOUND for replies.
senderstringYour Sender ID, Short Code or WhatsApp number.
recipientstringThe phone number, in international format.
text, image, video, audio, document, sticker, location, contacts, order, templateThe message, in the field named after its type, as you send it. order is a customer's order from your WhatsApp catalog: its catalogId and items (productId, quantity, price, currency). A file has its url (for a received file, a link that works for an hour), and its caption, mimeType, filename and size when known. A template has its id, name and language, and text holds what the customer read.
buttons, list, linkSent with text, as you sent them.
replyobjectSet when the customer tapped a button or quick reply, or picked a list row. Has the id you sent, the title they saw, and a row's description.
referralobjectSet when the customer wrote from your click-to-WhatsApp ad. Has the ad's headline, body, sourceUrl, sourceType, sourceId and clickId.
forwardedstringSet on a forwarded message. FORWARDED, or FREQUENTLY_FORWARDED if it has been forwarded many times.
contentstring or objectThe same message in the older shape. Text for SMS, WhatsApp's own format for WhatsApp.
statusstringQUEUED, SENT, DELIVERED, EXPIRED, UNDELIVERED, UNKNOWN or FAILED. See Delivery statuses.
failedReasonstring or nullWhy the message wasn't delivered. Set for EXPIRED, UNDELIVERED and FAILED.
failureCodestring or nullThe same reason as a code that never changes, such as E11001. Branch on it. See Why a message wasn't delivered.
costnumberWhat the message cost, in US dollars. Refunded if it ends as FAILED.
externalIdstringYour reference.
conversationIduuid or nullGroups a two-way conversation with one person, such as Short Code replies or a WhatsApp chat.
messageTypestring or nullTEMPLATE or FREE_FORM for WhatsApp. null for SMS.
inServiceWindowboolean or nullFor WhatsApp, whether the message went out inside the 24-hour window. null for SMS.
smsFallbackobjectWhatsApp only, if you sent one. Has sender, text and messageId. messageId is the SMS's ID once it's sent, and null until then. See If they're not on WhatsApp.
createdAtdate-timeWhen Ponitor accepted it.
updatedAtdate-timeWhen it last changed, usually its latest status.