MailerSend
WhatsApp API

Sending a WhatsApp message

Send template-based WhatsApp messages with the MailerSend WhatsApp API. Learn about senders, recipients, personalization and delivery tracking.

This endpoint allows you to send WhatsApp messages through the MailerSend WhatsApp API.

MailerSend sends WhatsApp messages through the WhatsApp Business Platform (Cloud API). Every business-initiated WhatsApp message must use a template that has been approved by Meta, so the API takes a template and the values for its variables instead of free-form message content.

Before you start

RequirementDetails
WhatsApp add-onWhatsApp is a paid add-on. Enable it in your MailerSend account before sending.
Connected senderConnect your WhatsApp Business Account (WABA) in WhatsApp → Phone numbers. The sender must stay connected for sending to work.
Approved templateCreate a template and submit it to Meta. Only templates with the approved status can be sent. Approval takes from a few minutes up to 48 hours.
API tokenUse a token with the whatsapp_full scope. See token scopes.

Templates and senders are managed in your MailerSend account. There are no API endpoints for creating senders or templates yet.

Send a WhatsApp message

This endpoint sends an asynchronous WhatsApp message to up to 10 recipients. It returns the ID of the created message in the response body and in the X-Message-Id header.

Send a WhatsApp message using this POST request:

POST https://api.mailersend.com/v1/whatsapp/send

Request Body

{
  "from": "15550001234",
  "to": [
    "+48600000001",
    "+48600000002"
  ],
  "template_id": "23zxk54v6gjy6v7m",
  "personalization": [
    {
      "to": "+48600000001",
      "data": {
        "header": [
          "Order #12345"
        ],
        "body": [
          "John",
          "December 31, 2026"
        ],
        "buttons": [
          "orders/12345"
        ]
      }
    },
    {
      "to": "+48600000002",
      "data": {
        "header": [
          "Order #12346"
        ],
        "body": [
          "Jane",
          "January 4, 2027"
        ],
        "buttons": [
          "orders/12346"
        ]
      }
    }
  ]
}
curl --request POST \
  --url https://api.mailersend.com/v1/whatsapp/send \
  --header 'Authorization: Bearer API_KEY_HERE' \
  --header 'Content-Type: application/json' \
  --data '{
    "from": "15550001234",
    "to": ["+48600000001"],
    "template_id": "23zxk54v6gjy6v7m",
    "personalization": [
      {
        "to": "+48600000001",
        "data": {
          "body": ["John", "December 31, 2026"]
        }
      }
    ]
  }'

Request parameters

JSON parameters are provided in dot notation

JSON parameterTypeRequiredLimitationsDetails
fromstringyesThe sender to send from. Must be one of your connected WhatsApp senders. See Sender identifiers.
tostring[]yesmin:1, max:10The recipients of the message. Each recipient must be unique within the request.
to.*stringyesA phone number in E.164 format, or a BSUID taken from an inbound message. WhatsApp usernames cannot be used as recipients. See Recipients.
template_idstringyesThe ID of an approved template that belongs to the sender in from. You can find it in WhatsApp → Templates.
personalizationobject[]nomax:10The values for the template's variables, per recipient. See Personalization.
personalization.*.tostringyesThe recipient the values apply to. Must be one of the values in to.
personalization.*.dataobjectyesObject containing the header, body and buttons sections.
personalization.*.data.headerstring[]noMax 60 characters per valueValues for the variables in the template header, in order.
personalization.*.data.bodystring[]noMax 1024 characters per valueValues for the variables in the template body, in order.
personalization.*.data.buttonsstring[]noMax 2000 characters per valueValues for the variables in the template's URL buttons, in order.

Sender identifiers

The from field accepts two forms of identifier. Both are scoped to your account and only resolve to a sender that is currently connected. You can find both in WhatsApp → Phone numbers.

FormExampleDetails
Phone number15550001234The sender's phone number in E.164 format.
MailerSend sender ID3enl6x27wmrxrl2vAlso returned as data.sender.id in every webhook payload.

A sender connected with a Meta virtual number has no phone number, so it can only be addressed by its MailerSend sender ID.

The MailerSend sender ID is stable across disconnecting and reconnecting a sender, which is not true of the phone number. Use it if you need a durable reference in your integration.

Recipients

Recipients can be addressed in two ways:

  • A phone number in E.164 format, for example +48600000001. Spaces, dashes, brackets, dots and the leading + are removed before the number is validated, so +48 600 000 001 and 48600000001 are the same recipient.
  • A BSUID (Business-Scoped User ID), for example US.13491208655302741918. Meta provides it in the payload of an inbound message, and it lets you reply to a user who contacted you without their phone number.

WhatsApp usernames cannot be used as recipients. Meta does not allow looking up a username, so use the recipient's phone number or the BSUID from their inbound message instead.

Personalization

Template variables are filled per recipient. Each entry in personalization targets one recipient from to and carries the values for the template's header, body and buttons sections.

Values are positional: the first value in the array replaces {{1}}, the second replaces {{2}}, and so on. Only variables in URL buttons are personalized, so the buttons array holds the URL parameters in the order the buttons appear in the template.

{
  "to": "+48600000001",
  "data": {
    "header": ["Order #12345"],
    "body": ["John", "December 31, 2026"],
    "buttons": ["orders/12345"]
  }
}

The number of values in each section must match the number of variables the template has in that section, for every recipient in to. A mismatch fails the whole request with a 422 response instead of failing per recipient after the message was queued:

{
  "message": "The given data was invalid.",
  "errors": {
    "personalization.0.data.body": [
      "The template expects 2 body variable(s) for 48600000001, 1 given."
    ]
  }
}

Authentication templates always expect exactly one body variable — the verification code. It is copied into the template's copy code button automatically, so leave buttons empty for them.

Objects with named keys, such as "body": {"name": "John", "date": "December 31, 2026"}, are also accepted. The values are used in the order they appear in the object, so a positional array is the safer choice.

Sandbox

The sandbox lets you test your integration without a connected WABA or an approved template. Activate it in WhatsApp → Sandbox, where you connect your own phone number to the MailerSend sandbox number and get the sandbox templates.

To send a sandbox message, use the sandbox number as the from value and one of the sandbox templates as the template_id. Sandbox sends are limited to 1 recipient per request and 20 messages per day, the sandbox connection expires after 1 hour, and sandbox messages are not counted against your monthly WhatsApp message cap.

Responses

Sending queued

Response Code: 202 Accepted
Response Headers:
	content-type: application/json
	X-Message-Id: 67f91abd69f79df391e9d78d
{
  "data": {
    "id": "67f91abd69f79df391e9d78d",
    "created_at": "2026-08-31 07:24:20"
  }
}

The message is accepted and queued. Each recipient is processed individually, and the delivery result for each one is reported through webhooks.

Missing permissions

Response Code: 403 Forbidden
Response Headers:
	content-type: application/json
{
  "message": "The custom API token you're using doesn't have the required permissions. #MS40301"
}

The token is missing the whatsapp_full scope.

No connected sender

Response Code: 403 Forbidden
Response Headers:
	content-type: application/json
{
  "message": "This action is unauthorized."
}

Your account has no connected WhatsApp sender, or the account is suspended.

Validation error

Response Code: 422 Unprocessable Entity
Response Headers:
	content-type: application/json
{
  "message": "The given data was invalid.",
  "errors": {
    "from": [
      "The from does not match any of your connected WhatsApp senders."
    ],
    "template_id": [
      "The selected template cannot be used for sending because it is in review. Only approved templates can be sent."
    ]
  }
}

See - Validation errors

Message rejected

Response Code: 422 Unprocessable Entity
Response Headers:
	content-type: application/json
{
  "error": "Failed to send WhatsApp message",
  "message": "We could not accept this WhatsApp message. Check that the sender is still connected and try again."
}

The request was valid but the message could not be accepted, most commonly because the sender was disconnected between your request and the send.

Common validation errors

ErrorCause
The from does not match any of your connected WhatsApp senders.The sender identifier is unknown, or the sender has been disconnected.
The to.0 must be a valid phone number or BSUID.A recipient is not a valid E.164 phone number or BSUID.
The to.0 cannot be a WhatsApp username.Usernames cannot be used as recipients. Use a phone number or a BSUID.
Maximum 10 recipients allowed.Split the request into batches of up to 10 recipients.
Each recipient can only be listed once per request.The same recipient appears more than once in to.
The selected template does not exist.The template ID is unknown or the template was deleted.
The selected template cannot be used for sending because it is <status>.Only approved templates can be sent.
The selected template belongs to a different WhatsApp sender.Use a template that was created for the sender in from.
WhatsApp sending has been paused. You have reached your monthly message cap.The account has reached the message cap of its WhatsApp add-on for the current billing period.

Tracking delivery

WhatsApp messages are sent asynchronously, so the 202 response only means the message was accepted. To learn what happened to each recipient's message, create a webhook for your sender and listen for the whatsapp.sent, whatsapp.delivered, whatsapp.read and whatsapp.failed events. Inbound messages from your recipients are delivered as whatsapp.inbound events.

Read more about WhatsApp webhooks.

Data retention

WhatsApp messages, activity and webhook logs are kept for 7 days. Store anything you need for longer in your own system, for example by consuming webhook events.

On this page