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? Go to our Agency Partners page, click Get Matched, and fill out the form; we’ll pair you with an agency that can help you create a transactional migration plan.

Prerequisites for the Transactional API

  • Your registration email must be confirmed and your account verified for sending.
  • Your sending domain must be authenticated. If you have configured a custom SMTP server, contact us at to manually authenticate your sending domain.
  • 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.

You can find the transactional_message_id in a few places:

  • In code sample the Send Message step when you set up your message.
  • In the code sample in the Overview tab after you set up your message.
  • In the URL when you select a transactional message in the user interface. The number immediately following /transactional/ is the transactional_message_id.
  • You can return a list of your transactional messages, each containing the id (short for transactional_message_id) from the Transactional API.

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.



One key difference between and other transactional messaging providers is the customer-centric approach to messaging. You must specify an identifierThe attributes you use to add, modify, and target people. Each unique identifier value represents an individual person in your workspace. for a person, one of id, email, or cio_id (depending on the identifiers allowed by your workspace) in your send API request, which creates a new profile or matches an existing profile in the workspace.

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 @-

Schedule your message

You can use the send_at parameter in your transactional API request to schedule your message for up to 90 days in the future. This helps if customers sign up for time-sensitive transactional messages, so you don’t have to manually schedule your transactional API requests in your backend system.

You might use send_at to send booking reminders as a person’s vacation rental or event approaches. Or you might let customers who expressed interest in a product before it’s released know exactly when it becomes available.

By default, we retain the content of the messages you send and track links in transactional messages. However, you might not want to do this for transactional emails with sensitive information—personal customer information, password reset tokens, etc. For sensitive messages, you can enable the Protect sensitive data setting. This setting prevents from storing the body of transactional messages.

However, when you enable the Protect sensitive data setting, you also necessarily disable link tracking in your message because we don’t retain the message.

with protect sensitive data enabled, we can't track messages
with protect sensitive data enabled, we can't track messages

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. Your payload changes based on whether you reference a transactional_message_id (a template) or not. See our REST API documentation for more information.

  • transactional_message_id integer
    Required The transactional message that you want to send. When you set up a transactional message in, it functions as a template that you call by ID.
  • body string
    The body of your message. This overrides the body of the transactional template (referenced by transactional_message_id).
  • from string
    The address that your email is from. This address must be verified by This overrides the from address set within the transactional template (referenced by transactional_message_id). You can include a display/friendly name in your from address in the format Person <>.
  • subject string
    The subject line for your message. This overrides the subject of the transactional template (referenced by transactional_message_id).
  • attachments array of [objects]
    A dictionary of attachments where the filename is the key and the value is the base64-encoded contents. The total size of all attachments must be less than 2 MB. Some filetype extensions are restricted.
  • bcc string
    Blind copy message recipients. Supports multiple addresses separated by commas. Your request can contain up to 15 total recipients between the to and bcc keys.
  • disable_css_preprocessing boolean
    Set to true to disable CSS preprocessing. This setting overrides the CSS preprocessing setting on the transactional_message_id as set in the user interface. Transactional emails have CSS preprocessing enabled by default.
  • disable_message_retention boolean
    If true, the message body is not retained in delivery history. Setting this value overrides the value set in the settings of your transactional_message_id.
  • fake_bcc boolean
    If true, rather than sending true copies to BCC addresses, sends a copy of the message with the subject line containing the recipient address(es).
  • headers array of [objects]
    Headers must be strings and cannot contain any non-ASCII characters or empty spaces. Some headers are reserved and cannot be overwritten.
  • identifiers One of:
    Required Identifies the person represented by your transactional message by one of, and only one of, id, email, or cio_id.
    • id string
      Required The identifier for the person represented by the transactional message. NOTE: If your workspace identifies people by email, use the email identifier instead.
    • Liquid Data* any type
      Insert key-values that you want to reference in your message here.
  • plaintext_body string
    By default, we generate a plaintext version of your message body for each delivery. Use this key to override the default plain text body.
  • preheader string
    Also known as “preview text”, this is the block block of text that users see next to, or underneath, the subject line in their inbox.
  • queue_draft boolean
    If true, your transactional message is held as a draft in and not sent directly to your audience. You must go to the Deliveries and Drafts page to send your message.
  • reply_to string
    The address that recipients can reply to, if different from the from address.
  • send_at integer
    A unix timestamp determining when the message will be sent. The timestamp can be up to 90 days in the future. If this value is in the past, your message is sent immediately.
  • send_to_unsubscribed boolean
    If false, your message is not sent to unsubscribed recipients. Setting this value overrides the value set in the settings of your transactional_message_id.
  • to string
    Required The message recipient(s). Supports multiple addresses separated by commas. Your request can contain up to 15 total recipients between the to and bcc keys.
  • tracked boolean
    If true, tracks opens and link clicks in your message.


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.

How do I use the Transactional API with a custom SMTP server?

If you have configured a custom SMTP server and wish to use an unauthenticated sending domain, you’ll need to contact us at We’ll manually authenticate the record after confirming that you own the sending domain.

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 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?

If you have any questions or feedback not covered in this guide, please let us know at!

Copied to clipboard!
Is this page helpful?