Transactional API

Transactional messages are emails triggered from code in response to an action taken by a user in your app. Common use cases for transactional messages include:

  • Purchase receipts
  • Registration confirmations
  • Password resets
  • Trial expiration reminders
  • Comment notifications
  • Event reminders
  • Shipping updates
  • Support and feedback requests offers a Transactional API to support one-to-one messages like these, triggered directly from your app.

When to use the Transactional API

The Transactional API is ideal for separating transactional and marketing emails, while still being able to see and manage your messages in one platform. There is no extra cost for using this service.

Migrating from another provider

Migrations can be a daunting effort and we want to make sure the process is as clear and easy as possible. In this guide, you’ll find:

  • Instructions to set up your account (Prerequisites)
  • key terms and concepts
  • a step-by-step guide to help you create your first transactional message in

Ready to move your messages, but don’t have the time or resources to do it? Our professional services team is here to help. They’ll act as an extension of your own team to create a transactional migration plan and get you up and running the right way. Contact us at or schedule an initial consult.

Prerequisites for the Transactional API

  • Your registration email must be confirmed and your account verified for sending.
  • Your sending domain must be authenticated.
  • You must have an App API key to trigger your messages. App API keys are not the same as the Tracking API keys that you use to update profiles and trigger events. CIO does not store App API keys (only a hashed version) and you can restrict App API keys to specific IP addresses for extra security.
  • (Recommended) Designate the domain or subdomain you’ll use to send transactional messages. Using a different domain or subdomain for transactional messages protects your critical transactional messages from being affected by your marketing sends, which tend to have higher bounce and spam rates. Learn more about domain reputation.

Key Concepts for’s Transactional API

Sending Domains

A Sending Domain is the domain of the “From email address” when you send emails. Email providers (ie Gmail, Outlook, Yahoo) monitor the sending domain for unusual behavior and spam complaints.

To maintain high deliverability, we recommend assigning separate domains or subdomains for your marketing emails and your transactional emails. For example, your marketing emails might use while you send transactional emails from

Learn more about deliverability, domain reputation, and best practices for sending email.

Transactional IP Pool

By default, your domains are added to the shared IP pool for sending emails. We manage and monitor multiple pools to make sure they’re healthy and remove any poorly performing domains.

The transactional shared IP pool is separate from the default shared IP pool and requires even stricter bounce and spam thresholds to ensure that your transactional messages achieve the highest deliverability. Only domains used with the transactional service can send emails over this IP pool. Visit the Email Settings page to request that your domain be added to the transactional shared IP pool. When your domain is added to the transactional pool, you can no longer use it for campaigns or broadcasts.

You can also request dedicated IP addresses or set up a custom SMTP mail server from your Email Settings.


Transactional Message Template transactional_message_id

Each transactional message template that you create in your workspace has it’s own title, description, tags, content, and transactional_message_id. In the transactional API, you’ll use the transactional_message_id to indicate which message you want to populate and send.

While you can omit the transactional_message_id and populate your own message body, subject, and from values at send time, we recommend that you create a transactional message template for every type of message you plan to send (“Receipt”, “Password Reset”, etc), even if you want to populate a custom message at send time. attributes metrics for your transactional message to a transactional_message_id; if you don’t provide a transactional_message_id when you send your message, we attribute metrics to "transactional_message_id": 1. Using a transactional_message_id lets you gather and organize metrics for the different types of transactional messages that you send while still providing the flexibility to populate custom messages.

Uncategorized Messages

Any emails sent without a transactional_message_id are grouped in the “Uncategorized Messages” bucket and aggregated at the bottom of the Transactional List.


Identifer id

One key difference between and other transactional messaging providers is the customer-centric approach to messaging. You must specify the profile id in your send API request, which creates a new profile or matches an existing profile in the workspace.

 Customer id’s in

The id is unique and cannot be changed. We recommend using customer database identifiers from your app, or consulting your technical team to determine what id values work best for your messaging needs.

Trigger Data and Content Variables

When using a transactional message template, you can customize your message using Liquid. To reference customer attributes in your content, use {{customer.____}} just as you would in any other message in

To reference data that you pass in the API, use {{trigger.____}}. Then, in your API request, include a message_data object that defines the values for trigger placeholders.

Below is an example showing a password reset message and the API request to trigger it.

  "to": "",
  "transactional_message_id": 3,
  "message_data": {
    "first_name": "Sarah",
    "passwordResetURL": ""
  "identifiers": {  

echo $message | curl -v \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer APP-API-TOKEN' \
-d @-

Creating a Transactional Message

1. Create a message.

Go to the Transactional page and click Create message. If this is your first transactional message, you’ll see an overview of the transactional product with a call-out to “Send your first message”.


2. Name your message and provide a description.

Enter an informative title and description that lets team members and future visitors know what kind of message this will be (ie “Password Reset Instructions”).


3. Choose your content source.

If you plan to create and manage your message in, choose “Create content in”. If you store your message in code and prefer to keep it that way, choose “Send content via the API”.


Not sure? Start with “Create content in”. We recommend this approach because it allows you to reuse existing layouts or email templates, make future updates easily, and test your messages in before integrating transactional API calls into your app.

4. Add content

Skip this step if you’re sending the content via API. Choose your editor (Drag and drop, Rich text, or Code), or start from an existing email from your campaigns or broadcasts. You can use customer attributes or API trigger data to customize your message.

5. Configure message settings.

Send to unsubscribed people? Unsubscribed people may still need important transactional messages. The FTC provides guidelines about what qualifies as a transactional message, including what to do for messages that combine transactional and marketing content.

Enable open and link tracking? Enable this setting if you need to know if people open or click links in your transactional messages.

Protect sensitive data by disabling message retention? Enabling this setting prevents CIO from retaining message content in delivery history, and prevents the message body from displaying when you view sent deliveries or retrieving them via API. You might want to do this to conceal sensitive content, like password reset tokens.

Queue messages as drafts? Enable this setting generate a draft for every triggered message, instead of sending them to recipients automatically. You can review these messages under the “Drafts” tab and decide whether to send or delete them.

6. Send your message

To complete the setup, you need to call the API and trigger a message. If you’re not yet ready to integrate this message into your code, you can use an HTTP client like Postman or call the cURL request directly from your terminal to test your message and complete the setup.


List of Supported Parameters

This is a list of parameters for transactional message payloads. See our REST API documentation for more information.

Parameter Req’d? Description
to Required The message recipient. Must be a valid email address. Use the format "Name <>" to include a display name. Each request can contain a maximum of 15 recipients, comma-separated, across the To and BCC fields.
identifiers Required The unique identifier for the customer, used to match the delivery with the correct profile in your workspace. "identifiers":{"id":"CUSTOMER ID"}
transactional_message_id Optional The unique identifier for the transactional message template that you want to use. If your message template includes a from address, subject, and body, you do not need to provide these in the request.
message_data Optional Custom data to populate Liquid placeholders in your message template. Use {{trigger.variable_name}} to reference this data in your template.
from Required* The address that your message is from. Must be a valid email address with a verified domain. Not required if using transactional_message_id. If you include both a transactional_message_id and a from address, the address in your request overwrites the values in the message template.
subject Required* The subject line of your email. Not required if using transactional_message_id. If you include both a transactional_message_id and a subject, the subject in your request overwrites the values in your message template.
body Required* The message body of your email. Not required if using transactional_message_id. If you include both a transactional_message_id and a body, the body in your request overwrites the values in the message template. Note: If you want to track links in your message body, populate links using liquid (e.g. {{trigger.custom_url}}) or you will generate a new tracked link for each message you send.
bcc Optional The blind copy recipient(s) of your message. Must be a valid email address. Use the format "Name <>" to include a display name. Each request can contain a maximum of 15 recipients, comma-separated, across To and BCC fields.
fake_bcc Optional Defaults to true. When true, recipients are copied on emails and can open them and click links without affecting the recipient’s history. Learn more about fake_bcc.
reply_to Optional The address recipients can reply to. Must be a valid email address. Use the format "Name <>" to include a display name.
preheader Optional Also known as “preview text”, this specifies the small block of text shown in an end-user’s email inbox, next to, or underneath, the subject line.
plaintext_body Optional By default, CIO generates a plaintext version of your message body for each delivery. Use this parameter to override the default plain text body.
attachments Optional An array of Base64-encoded attachments. Total attachment size cannot exceed 2 MB. Some restrictions on filetype extensions apply.
headers Optional Custom headers must be strings and not contain any non-ASCII characters or empty spaces. Some headers are reserved and cannot be overwritten.
disable_message_retention Optional Set to true to prevent the message body from being retained in delivery history. Set this value in your request to override the default value (false) or the value set in transactional message settings (if using transactional_message_id).
send_to_unsubscribed Optional Set to false to prevent your message from sending to unsubscribed recipients. Set this value in your request to override the default value (true) or the value set in the transactional message settings (if using transactional_message_id).
tracked Optional Set to true to track opens and clicks. Set this value in your request to override the default value (true) or the value set in the transactional message settings (if using transactional_message_id).
queue_draft Optional Set to true to queue messages instead of sending to the specified recipient. Set this value in your request to override the default value (false) or the value set in your transactional message settings (if using transactional_message_id).


Does using the transactional API cost extra?

There’s no extra cost. You can start sending transactional messages immediately alongside your other messages.

When should I use the ‘disable message retention’ setting?

Disabling message retention is helpful for concealing sensitive content, like password reset tokens. Turning on this setting prevents message content from displaying in your workspace when viewing sent deliveries or retrieving messages via API. Instead, team members will see the following screen:


When should I use the Transactional API vs event-triggered campaigns?

The transactional service is best for sending a email to a single person, typically in response to a customer action. Transactional email examples include:

  • Receipts
  • Password reset requests
  • Account alerts

For emails that require multiple messages (like welcome campaigns) or branching (e.g. multiple channels, multiple languages, or A/B testing), you should continue using event-triggered campaigns.

When should I use the Transactional API vs API-triggered Broadcasts?

API triggered broadcasts are optimized for sends that go to many people at a time (ie marketing blasts). These broadcasts can be configured to send to an entire segment(s) at a time, and are thus limited to a rate of 10 requests/second, with dedicated messaging queues to manage the high volume.

The Transactional API is optimized to send transactional messages to one recipient at a time (ie order confirmations), and should not be used to send marketing blasts. They have a limit of 15 total recipients across To and BCC fields, a higher rate limit of 100 requests/second, and also have dedicated sending lanes to ensure a quick delivery.

How many people can I message within a single Transactional API call?

A single API request can contain a maximum of 15 recipients. This includes all recipients across both the To and BCC fields.

Can I schedule a message to send in the future?

No, it’s not currently possible to schedule a transactional message to send at a future time.

I need to support multiple languages or channels. How do I accomplish this with transactional messages?

Multi-language and multi-channel support are high on our list of priorities, but not yet easily accomplished in a single template. Instead, you must use [Liquid]/using-liquid) or create a transactional messages for each language or channel and trigger the appropriate message from code. You can also use branches in event-triggered campaigns to manage these messages.

Why isn’t there an option to CC someone on an email?

With’s profile-based messaging approach, we don’t include CC options across the platform because of potential complications in open and link tracking. Instead, use multiple addresses in the TO field or use BCC to include additional recipients on your messages.

Can I A/B test transactional messages?

For A/B testing, use API-triggered broadcasts or event-triggered campaigns.

Can I use the transactional API to send Push or SMS messages?

To send transactional push or SMS messages, use API-triggered broadcasts or event-triggered campaigns.

Can I use the transactional API to send bulk marketing sends?

The transactional API is not optimized for bulk marketing sends. Use API-triggered broadcasts instead.

What attachment file types are forbidden?

bat, bin, chm, com, cpl, crt, exe, hlp, hta, inf, ins, isp, jse, lnk, mdb, msc, msi, msp, mst, pcd, pif, reg, scr, sct, shs, vbe, vba, vbs, wsf, wsh, wsl

What headers are reserved and cannot be overwritten in the API request?

Authentication-Results, Auto-Submitted, Content-Alias, Content-Base, Content-Disposition, Content-ID, Content-Identifier, Content-Length, Content-Transfer-Encoding, Content-Type, Encoding, Lines, Mail-System-Version, Mailer, Mime-Version, Originating-Client, Received, Received-SPF, Return-Path, VBR-Info, X-Mailer, X-Report-Abuse-To

Have additional questions?

This is a new feature, and we want to make it as useful and intuitive as possible. If you have any questions or feedback, please let us know!

Copied to clipboard!