Send a batch of messages

POST/api/v1/messages/batch
Requires anorganization API keywith the scopemessages:send

One shared template and a list of recipients, each with their own variables. Up to 500 recipients per call.

A partial failure is not an error. Every recipient is processed independently, so one suppressed or malformed address does not stop the rest — the call still returns 200 and the per-recipient outcome is in results. Check failed rather than the status code, or you will silently lose mail you believe you sent.

This is for transactional mail going to many people at once. For marketing sends to a list or segment, use campaigns instead: they add unsubscribe handling, review and reporting that this endpoint deliberately does not.

Parameters

NameInTypeDescription
Idempotency-KeyheaderstringMakes this request safe to retry. Use <app>-<ULID>, such as crm-01JBT8XQ2M9WYC3K4F6R7S8T9V; any other shape is a 422. Send the same key on every retry: a repeat gets the first answer with Idempotency-Replayed: true, a key reused for a different request is a 422, and one still running is a 409 with Retry-After. Keys last 24 hours, per organization.

Request body

  • messagesarray<object>required

    The recipients, 1 to 500, each with their own variables.

    • tostringrequired

      This recipient's address.

    • variablesobject

      Values for this recipient's {{ tags }}, like {"name": "Ada"}.

  • fromstringrequired

    The sender address for every message. It must be a verified sender in your organization.

  • subjectstring

    The subject for every message. It can use {{ tags }}. Needed unless template_id is given.

  • htmlstring

    The HTML for every message, with {{ tags }} filled from each recipient's variables.

  • textstring

    The plain-text version of the email.

  • template_idstring

    Optional. One of your templates to use instead of subject and html.

  • tagsarray<string>

    Your own labels, returned on the delivery events for these messages.

Request

POST/api/v1/messages/batch
curl -X POST 'https://app.mailyte.com/api/v1/messages/batch' \
  -H 'Authorization: Bearer mk_live_YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "from": "hello@yourdomain.com",
    "subject": "Your weekly summary",
    "template_id": "01JBT8XQ2M9WYC3K4F6R7S8T9V",
    "messages": [
      {
        "to": "ada@example.com",
        "variables": {
          "first_name": "Ada"
        }
      },
      {
        "to": "grace@example.com",
        "variables": {
          "first_name": "Grace"
        }
      }
    ]
  }'
The key names its own organization, so no X-Organization-ID header is needed.

Response

The batch was processed. Individual recipients may still have failed — check `failed`.

  • dataobject
    • objectstringbatch
    • sentinteger

      Rows where accepted is true.

    • failedinteger

      Rows where accepted is false. A refused recipient is a row, never a failed request: sent + failed always equals results length.

    • resultsarray<object>

      One row per recipient, in the order submitted.

      • recipientstring

        The recipient this row is about, as you sent it.

      • acceptedboolean

        The ONLY field to branch on. Every row carries every key, so a missing id never has to be read as a success.

      • idstring

        Mailyte's ID for this recipient's copy, like id on POST /messages. Null when accepted is false.

      • message_idstring

        The RFC 5322 Message-ID for this recipient's copy, angle brackets included, for GET /domains/{domain}/messages/{messageId}. A different string from id, for a different endpoint. Null when accepted is false.

      • errorstring

        Why this recipient was refused, such as a suppressed or malformed address. Null when accepted is true.

200application/json
{
  "message": "Batch processed",
  "code": 200,
  "success": true,
  "data": {
    "sent": 1,
    "failed": 1,
    "results": [
      {
        "to": "ada@example.com",
        "message_id": "<01JBT8XQ2M@yourdomain.com>"
      },
      {
        "to": "grace@example.com",
        "error": "Recipient is suppressed."
      }
    ]
  }
}

Returned inside the standard envelope.

Errors

StatusWhen
401The API key is missing, unknown, revoked or expired. All four answer identically, on purpose: distinguishing them would confirm which keys exist.
403The key is valid but may not do this: it lacks the required scope, its IP allowlist does not include you, or this endpoint does not accept API keys.
404No such resource in this organization.
422The request was understood but the values were not acceptable.
429Too many requests, or the organization has spent its sending allowance. `Retry-After` says how long to wait.

Every status, with what causes it and what to do, is on the error reference.