Transactional messages

Transactional messages are emails that your audience implicitly opts-into, like a transaction receipt or a password reset request. In you use our Transactional API to send these messages.

How it works

A transactional message is a message your audience implicitly opts into, regardless of whether they’ve opted out of marketing messages or not—like purchase receipts, password reset requests, shipping updates, etc.

The Transactional API makes it easy to trigger this kind of message based on something a user does in your app or website. You can either create a transactional template in—a message that you’ll populate with data from an API call, or you can send your entire message body through the API.

In general, we recommend that you use the template option, because it’s easier to design a message in, reduces the size of the payload you need to store on your end, and it makes it easy to track engagement with your transactional messages. We aggregate metrics for all messages that don’t call a specific transactional_message_id—the template you create in—as “uncategorized messages”; so, if you send three different message bodies through our API without a transactional_message_id template, we’ll count the metrics for all three messages together.

 Moving from another provider and need help? Try our Agency Partners page.

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.

sequenceDiagram actor a as your user participant b as your website participant c as a->>b: request password reset b->>c: send transactional
API request c->>c: generate delivery c->>a: send password reset request

Use cases

The Transactional API helps you separate transactional and marketing emails, while still being able to see and manage both types of messages in the same platform. We don’t charge extra for this service! 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

Before you can send Transactional messages

Before you can send transactional messages you need to:

  • Confirm your registration email and verify your account.
  • Authenticate your sending domain. If you configured a custom SMTP server, contact us to manually authenticate your sending domain.
  • Get your App API key. This is the bearer token that you’ll use when calling the transactional API. 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.

We also recommend that you use a different, specialized domain or subdomain for transactional messages. A sending domain is the domain of the “From email address” when you send emails, and you can request that we add your transactional domain to our specialized, transactional IP pool. Email providers like Gmail monitor the sending domain for unusual behavior and spam complaints. Separating your transactional domain from your marketing domain—something like and—prevents your marketing messages from affecting your critical transactional messages. Learn more about domain reputation.

Create a Transactional Message

 Try our Postman collection!

You can use our Postman collection and associated environment to get started with the API. Our environment is based on our US endpoints; if you’re in our EU region, you’ll need to add -eu to track_api_url and app_api_url variables.

  1. Go to the Transactional page and click Send your first message or Create message—depending on whether there are already transactional messages in your workspace.


  2. Name your message and provide a description. These fields help your team members understand what kind of message this is (like “Password Reset Instructions”). You can also use the Name of your message instead of the transactional_message_id when you send your message.


  3. Click Add Content to create and manage your message template in (recommended). This generates the transactional_message_id that you’ll refer to when you send your message. If you store your message in code and prefer to keep it that way, choose “Send content via the API.


     Not sure where to start?

    In general, we recommend that you use the Create content in This approach lets you 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 your content (unless you want to send your full message in API requests). Choose your editor, or start from an existing email. When you build your email, you can personalize messages using attributes (customer.<attribute>) or API trigger data (trigger.<data-object-property>) to customize your message.

  5. Configure your message settings.

    • Send to unsubscribed people? Unsubscribed people probably still want to receive your 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? This setting prevents from retaining your message content in delivery history and associated API calls. You might want to do this to conceal sensitive content, like password reset tokens.

    • Queue messages as drafts? This setting generates a draft for every message you trigger, rather than sending them automatically. You can review these messages under the “Drafts” tab and decide whether to send or delete them.

    • Set a Trigger Name: This is a friendly name for your message that you can use instead of the transactional_message_id when you send your message. It may help make your integration more human-readable if you use triggers that represent the kinds of messages you send—like password reset or order confirmation.

    configure your message's settings
    configure your message's settings
  6. To complete the setup, you need to call the API and trigger a message. If you’re not yet ready to send a message directly from your code, you can use an HTTP client like Postman or send a cURL request from your terminal to test your message and complete the setup process.


Localize a transactional message

When you add content to your message, you can click Add language to select the languages you want to support. Then you can populate your languages, and we’ll automatically send your audience the language matching their language attributeA key-value pair that you associate with a person—like their name, the date they were created in your workspace, etc. Use attributes to target people and personalize messages..

 You can override languages when you send your message

If you don’t manage your audience’s language preferences in, or you need to override your audience’s language preference for any reason, you can set a language property in your transactional message request. Learn more

Add languages to your newsletter
Add languages to your newsletter

To take advantage of our localization feature, you must have set up an attribute to capture your audience’s language preference. See our localization section for more information about setting up multi-language messages.

When you send your message, we’ll match your audience’s language attributeA key-value pair that you associate with a person—like their name, the date they were created in your workspace, etc. Use attributes to target people and personalize messages.—their preferred language—with the languages in your transactional message. If a person’s language attribute matches a language in your transactional message, we’ll send them the appropriate language. If their language attribute does not match a language in your template, they’ll receive the default message.

graph LR A[Person completes
a transaction] --> B[Send transactional
api call] B --> D{Does a person's language
attribute match a message?} D -->|no| H[Person gets
default message] D -->|yes, lang=es| E[Person gets
Spanish message] D -->|yes, lang=fr| F[Person gets
French message] D -->|yes, lang=de| G[Person gets
German message]

Override your audience’s language

If you don’t manage your audience’s language preferences in, or you need to override your audience’s language preference for any reason, you can set a language property in your transactional message request. This value represents the language variant that you want to send to the recipient.

If the language doesn’t match one of your message’s languages, we’ll use the recipient’s language attributeA key-value pair that you associate with a person—like their name, the date they were created in your workspace, etc. Use attributes to target people and personalize messages.. If the language doesn’t match one of your message’s languages, and your audience doesn’t have a language attribute that matches one of your message’s languages, we’ll send the default message.

  "transactional_message_id": 44,
  "to": "",
  "from": "",
  "subject": "Did you really login from a new location?",
  "language": "es",
    "id": 12345
    "password_reset_token": "abcde-12345-fghij-d888",
    "account_id": "123dj"
  "bcc": "",
  "disable_message_retention": false,
  "send_to_unsubscribed": true,
  "tracked": true,
  "queue_draft": false,
  "disable_css_preprocessing": true

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 One of:
    Required The transactional message template that you want to use for your message. You can call the template by its numerical ID or by the Trigger Name that you assigned the template (case insensitive).
    The ID of the transactional message you want to send.
  • 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 <>.
  • language string
    Overrides language preferences for the person you want to send your transactional message to. Use one of our supported two- or four-letter language codes.
  • 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 (seconds since epoch) 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.

Key Concepts

Transactional IP Pool

By default, we add email domains to’s shared IP address pool to send emails. We manage and monitor multiple IP pools and remove domains that perform poorly to maintain high deliverability.

We also maintain a separate, transactional IP address pool. This pool has even higher standards—stricter bounce and spam thresholds than our default shared IP pool. This ensures that your transactional messages achieve the highest deliverability. Only domains used with the transactional service can send emails over this IP pool.

If you have a separate sending domain for your transactional messages, you can request that we add your domain to the transactional IP pool on the Settings > Workspace Settings > Email page. When we add a domain to the transactional pool, you can no longer use it to send 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

When you create a transactional message with the Add Content option, it generates a transactional_message_id. You’ll use this value to indicate which of your transactional messages you want to populate and send.

 You can use your message’s Trigger Name rather than the ID

When you create your transactional message in, you can assign it a Trigger Name. When you send a transactional message, you can pass the Trigger Name as the transactional_message_id, which can make it easier to know what kinds of transactional messages you’re sending and when!

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.

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.

Uncategorized Messages

Messages sent without a transactional_message_id are grouped as “Uncategorized Messages” and aggregated at the bottom of the Transactional List.


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.<attribute>}} 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

Update the contents of your message

You can update the contents of your message through our user interface. Changes to your message take effect immediately: any messages you trigger after your update will use the new content.

We’ve also exposed an API endpoint, so you can manage your message contents programmatically. This request takes a body, which represents the complete HTML content of your message.

curl --request PUT \
  --url{transactional_id}/content/{content_id} \
  --header 'Authorization: Bearer REPLACE_BEARER_TOKEN' \
  --header 'content-type: application/json' \
  --data '{"body":"string"}'
Copied to clipboard!
Is this page helpful?