Transactional Email API
The Transactional Email API allows you to programmatically send individual, personalized emails triggered by specific events in your application.
Required Permissions
All endpoints require authentication via an API token with appropriate permissions:
- View transactional email details (Read)
- Send transactional emails (Write)
Transactional Email Object
The transactional email object contains the following fields:
| Field | Description |
|---|---|
| `id` | The unique identifier of the transactional email |
| `recipient_email` | The email address of the recipient |
| `recipient_name` | The name of the recipient (optional) |
| `subject` | The subject line of the email |
| `body` | The content of the email |
| `preheader` | Preview text that appears in email clients |
| `reply_to` | Reply-to email address for this transactional email |
| `sender_identity_id` | ID of the sender identity (From address) to send as; omit to use the channel default |
| `queue_at` | The scheduled time for sending the email |
| `sent_at` | The time when the email was sent |
| `created_at` | The time when the record was created |
| `updated_at` | The time when the record was last updated |
| `status_url` | URL to check the status of this transactional email |
Send Transactional Email
POST /api/v1/transactionals.json
Parameters
to(required): Email address of the recipientsubject(required, unlesstemplate_idis provided): Subject line of the emailbody(required, unlesstemplate_idis provided): Content of the email, which can be either a simple string or HTML. In either case, Broadcast will wrap the content in the appropriate html and body tags. If you want to incorporate an entire HTML design, just send the contents within the body tag.template_id(optional): ID of an email template to use. The template’s body, subject, and preheader are used as defaults. Explicitbody,subject, orpreheaderparams override the template values.reply_to(optional): Reply-to email address for this transactional emailsender_identity_id(optional): ID of the sender identity to send as (must belong to the channel); omit to use the channel defaultinclude_unsubscribe_link(optional): Set totrueto include an unsubscribe link. Defaults tofalse.
Request
curl -X POST \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ --data-raw '{ "to": "recipient@example.com", "subject": "Welcome to Our Service", "body": "Thank you for signing up!", "reply_to": "support@example.com" }' \ https://your-broadcast-domain.com/api/v1/transactionals.json
Response
{ "id": "123", "recipient_email": "recipient@example.com", "recipient_name": null, "subject": "Welcome to Our Service", "body": "Thank you for signing up!", "preheader": null, "reply_to": "support@example.com", "queue_at": "2024-03-21T10:00:00Z", "sent_at": null, "created_at": "2024-03-21T09:00:00Z", "updated_at": "2024-03-21T09:00:00Z", "status_url": "https://your-broadcast-domain.com/api/v1/transactionals/123.json" }
Note: The recipient_name field is populated from subscriber data if the email matches an existing subscriber. The preheader field is reserved for future use.
If the request is invalid, the response code will be 422 (Unprocessable Entity). The error message will be returned in the response body:
{ "errors": { "recipient_email": ["can't be blank"], "subject": ["can't be blank"], "body": ["can't be blank"] } }
Send Transactional Email Using a Template
Instead of providing the email content inline, you can reference an existing template by its ID. The template’s body, subject, and preheader are used as defaults, and any explicit parameters override the template values.
Request
curl -X POST \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ --data-raw '{ "to": "recipient@example.com", "template_id": 123 }' \ https://your-broadcast-domain.com/api/v1/transactionals.json
You can override specific template fields:
curl -X POST \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ --data-raw '{ "to": "recipient@example.com", "template_id": 123, "subject": "Custom subject override" }' \ https://your-broadcast-domain.com/api/v1/transactionals.json
The template must belong to the same channel as the API token. If the template is not found, a 422 error is returned.
Double Opt-In via Transactional Email
Send a confirmation email using your own email content via the transactional API. When double_opt_in is set to true, a subscriber is automatically created (if one doesn’t exist) and {{ confirmation_url }} becomes available as a Liquid variable in your email body.
Parameters
double_opt_in(required): Set totrueto enable double opt-inconfirmation_template_id(optional): ID of a confirmation template whose page copy (heading and body, customizable per page state) is displayed on the confirmation page after the subscriber clicks the link. If omitted, the confirmation page resolves to the channel’s default confirmation template, then to Broadcast’s English defaults.subscriber(optional): An object with subscriber attributes for the auto-created subscriberfirst_name: First namelast_name: Last name
Request
curl -X POST \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ --data-raw '{ "to": "user@example.com", "subject": "Confirm your subscription to Acme Newsletter", "body": "<p>Hi {{ first_name }},</p><p>Thanks for signing up! Please <a href=\"{{ confirmation_url }}\">confirm your subscription</a> to start receiving our newsletter.</p><p>If you did not sign up, you can ignore this email.</p>", "double_opt_in": true, "subscriber": { "first_name": "John", "last_name": "Doe" } }' \ https://your-broadcast-domain.com/api/v1/transactionals.json
Response
{ "id": 123, "recipient_email": "user@example.com", "subject": "Confirm your subscription to Acme Newsletter", "status": "queued", "confirmation_status": "pending", "confirmation_url": "https://your-broadcast-domain.com/confirm/abc123token", "status_url": "https://your-broadcast-domain.com/api/v1/transactionals/123.json" }
What happens
- A subscriber is auto-created (unconfirmed) if one doesn’t already exist
- A confirmation record is created with a unique token
- Your transactional email is sent with
{{ confirmation_url }}resolved to the real confirmation link - When the subscriber clicks the link, they are confirmed
Behavior by subscriber state
| Subscriber State | Behavior |
|---|---|
| Does not exist | Created as unconfirmed. Transactional email sent with {{ confirmation_url }} resolved. |
| Exists, unconfirmed | New confirmation created. Transactional email sent with fresh {{ confirmation_url }}. |
| Exists, confirmed | double_opt_in ignored. Transactional email sent normally. {{ confirmation_url }} renders blank. |
Available Liquid Variables
When double_opt_in is true, the following variables are available in your email body in addition to the standard transactional variables:
| Variable | Description |
|---|---|
{{ confirmation_url }} |
The confirmation link (only populated when subscriber is unconfirmed) |
{{ email }} |
Recipient’s email address |
{{ first_name }} |
Recipient’s first name |
{{ last_name }} |
Recipient’s last name |
{{ name }} |
Full name |
{{ unsubscribe_url }} |
Unsubscribe link (if include_unsubscribe_link: true) |
Idempotent Requests
Sending the same transactional email twice — for example, when a network timeout
makes your client retry — costs real deliverability. To make retries safe, pass an
Idempotency-Key header on POST /api/v1/transactionals: an opaque string of your
choosing (up to 255 characters), unique per logical send.
Idempotency-Key: order-12345-receipt
Behavior:
- First request with a key is processed normally and its response is stored.
- Retrying with the same key and the same request body does not send again — the
stored response is replayed, with an
Idempotency-Replayed: trueresponse header. - Reusing a key with a different request body fails with
422— a key identifies one logical request, never two. - Retrying while the first attempt is still processing returns
409; retry after a short delay. - Keys are scoped to the API token that sent them and expire after 24 hours. The
request identity covers the full URL including the query string — the same key
with a different
broadcast_channel_idis a different request. - Responses with server errors (5xx) are not stored, and neither is any response produced by a raised error — such retries are processed fresh.
- Requests without the header behave exactly as before.
Get Transactional Email Details
GET /api/v1/transactionals/:id.json
Parameters
id(required): The ID of the transactional email
Request
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ https://your-broadcast-domain.com/api/v1/transactionals/123.json
Response
{ "id": "123", "recipient_email": "recipient@example.com", "recipient_name": null, "subject": "Welcome to Our Service", "body": "Thank you for signing up!", "preheader": null, "reply_to": "support@example.com", "queue_at": "2024-03-21T10:00:00Z", "sent_at": "2024-03-21T10:00:05Z", "created_at": "2024-03-21T09:00:00Z", "updated_at": "2024-03-21T10:00:05Z", "status_url": "https://your-broadcast-domain.com/api/v1/transactionals/123.json" }
Unsubscribe Behavior
Transactional emails bypass unsubscribe status. Unlike marketing emails (broadcasts and sequences), transactional emails will be delivered even if the recipient has unsubscribed from your mailing list.
This is by design and follows industry standards (CAN-SPAM, GDPR) which distinguish between marketing communications and essential service-related messages like:
- Password reset emails
- OTP/verification codes
- Account confirmation emails
- Order receipts and shipping notifications
Exceptions: Transactional emails will still be blocked if:
- The recipient is a redacted subscriber (GDPR data deletion request)
- The recipient is on the global suppression list (typically due to hard bounces)
Notes
- When sending a transactional email, if no specific queue time is provided, the email will be queued immediately.
- If the recipient’s email matches an existing subscriber in your database, the transactional email will be automatically associated with that subscriber’s record.
- All API requests must include a valid API token with the appropriate permissions in the Authorization header.