> This page is part of the [Customer.io documentation](https://docs.customer.io). For the complete index, see [llms.txt](https://docs.customer.io/llms.txt).
> Last updated: July 10, 2026

# Trigger inbox messages from your backend

You can send inbox messages in response to user activity directly from your backend. While we call this a *transactional* message, it’s not a transactional message in the traditional, legal sense—it’s a message that you send to your audience that they can access at their leisure.

## How it works

You can leverage our transactional messaging feature to send inbox messages immediately from your backend without triggering a campaign or broadcast. This gives you a way to send one-to-one messages using Customer.io without having your message-sending logic inside Customer.io.

1.  **[Set up a message template](#1-set-up-a-message)**: This represents the “template” for the message you want to send. You’ll also use [liquidA syntax that supports variables, letting you personalize messages for your audience. For example, if you want to reference a person’s first name, you might use the variable `{{customer.first_name}}`.](/journeys/liquid/using-liquid) to personalize the message for the recipient.
2.  **Set up your backend to trigger your inbox message**: This is where you’ll send the message payload to Customer.io. You’ll reference the template to make sure that you send the correct message.

## 1\. Set up a message

A transactional inbox message is a reusable template that you trigger from your backend. You author the content once and reference the message by its trigger name or ID when you send it.

1.  Go to the **Transactional** page and click **Create Message**.
2.  Give your message a *Name* and a *Description*, then click **Next: Add Content**. The name and description help your team members understand what kind of message this is (like “Order Update”).
3.  Select **Inbox** as the message type, pick your editor, and then click **Next: Configure Settings**. In most cases, we recommend using the **Visual** editor.
    *   **Visual**: See [build a message in the visual editor](/messaging/channels/in-app/inbox/send-inbox/#build-a-message-in-the-visual-editor) for more about creating your message. You’ll choose a layout, add content, and set the expiration period for your message.
    *   **Advanced**: provide a free-form JSON payload if you [build your own inbox](/messaging/channels/in-app/inbox/advanced/overview/).
        
        [![The inbox message type selection screen with the inbox message type selected](https://docs.customer.io/images/inbox-content.png)](#3c5395496b6eb2d00967b0ac744565ec-lightbox)
        
4.  Save your message and click **Next: Configure Settings**.
5.  Update your message settings. You should **Set a trigger name** so that it’s easy to reference your message later. By default, you’ll trigger a message using the `transactional_message_id`, which is the last number in the URL of your message; the trigger name makes this more human readable. Otherwise, we recommend that you use the default settings.
    
    [![The inbox message settings screen with the message settings filled in. The trigger name is set to example_message.](https://docs.customer.io/images/inbox-message-settings.png)](#87a9be50589a8a66231464c1b8251664-lightbox)
    
6.  Click **Next: Send Message**.

Now you’re ready to [trigger your message from your backend](#2-set-up-your-backend-to-trigger-inbox-messages).

### Personalize your message with liquid

Whichever editor you use, you can personalize your message content with [liquidA syntax that supports variables, letting you personalize messages for your audience. For example, if you want to reference a person’s first name, you might use the variable `{{customer.first_name}}`.](/journeys/liquid/using-liquid). This is especially useful for transactional messages, where you pass data in the `message_data` object when you trigger the message.

*   **Customer [attributesA key-value pair that you associate with a person or an object—like a person’s name, the date they were created in your workspace, or a company’s billing date etc. Use attributes to target people and personalize messages.](/journeys/people/manage/attributes/)**: attributes already set on your audience. For example, `{{customer.first_name}}` corresponds to the `first_name` attribute on the recipient’s profile.
*   **Trigger data**: data sent in the `message_data` object when you trigger the message. For example, `{{trigger.order_number}}` corresponds to `message_data.order_number` in your payload.

## 2\. Set up your backend to trigger inbox messages

You trigger inbox messages by sending a `POST` request to `https://api.customer.io/v1/send/inbox_message`. Authenticate with an App API key in the `Authorization` header.

The analytics JavaScript library you use for in-app messaging doesn’t send transactional messages, so you call this endpoint directly from your backend with your own HTTP client. See our [API documentation](/integrations/api/app/#operation/sendInboxMessage) for the full reference.

Your request body includes:

*   `transactional_message_id`: The ID of your transactional message. You can find this in the URL of your transactional message or in the code sample in the **Overview** tab for your transactional message.
*   `identifiers`: The identifiers for the recipient. You can use the `id`, `email`, or `cio_id` identifier.
*   `message_data`: The data you want to include in your message. You can reference this data in your message with [liquidA syntax that supports variables, letting you personalize messages for your audience. For example, if you want to reference a person’s first name, you might use the variable `{{customer.first_name}}`.](/journeys/liquid/using-liquid).

The examples below send the same request with cURL and a few common languages. Adapt them to your stack.

 cURL

#### cURL

```bash
curl --request POST \
  --url https://api.customer.io/v1/send/inbox_message \
  --header 'Authorization: Bearer YOUR_APP_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "transactional_message_id": "order_shipped",
    "identifiers": {
      "id": "user_123"
    },
    "message_data": {
      "order_id": "ORD-5678",
      "tracking_url": "https://track.example.com/5678",
      "product_name": "Blue Widget"
    }
  }'
```

 Node.js

#### Node.js

```javascript
const response = await fetch("https://api.customer.io/v1/send/inbox_message", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_APP_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    transactional_message_id: "order_shipped",
    identifiers: { id: "user_123" },
    message_data: {
      order_id: "ORD-5678",
      tracking_url: "https://track.example.com/5678",
      product_name: "Blue Widget",
    },
  }),
});

console.log(response.status, await response.json());
```

 Python

#### Python

```python
import requests

response = requests.post(
    "https://api.customer.io/v1/send/inbox_message",
    headers={"Authorization": "Bearer YOUR_APP_API_KEY"},
    json={
        "transactional_message_id": "order_shipped",
        "identifiers": {"id": "user_123"},
        "message_data": {
            "order_id": "ORD-5678",
            "tracking_url": "https://track.example.com/5678",
            "product_name": "Blue Widget",
        },
    },
)

print(response.status_code, response.json())
```

 Ruby

#### Ruby

```ruby
require "net/http"
require "json"
require "uri"

uri = URI("https://api.customer.io/v1/send/inbox_message")

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer YOUR_APP_API_KEY"
request["Content-Type"] = "application/json"
request.body = {
  transactional_message_id: "order_shipped",
  identifiers: { id: "user_123" },
  message_data: {
    order_id: "ORD-5678",
    tracking_url: "https://track.example.com/5678",
    product_name: "Blue Widget"
  }
}.to_json

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

puts response.code
puts response.body
```

 Go

#### Go

```go
package main

import (
	"bytes"
	"fmt"
	"net/http"
)

func main() {
	body := []byte(`{
		"transactional_message_id": "order_shipped",
		"identifiers": {"id": "user_123"},
		"message_data": {
			"order_id": "ORD-5678",
			"tracking_url": "https://track.example.com/5678",
			"product_name": "Blue Widget"
		}
	}`)

	req, _ := http.NewRequest("POST", "https://api.customer.io/v1/send/inbox_message", bytes.NewBuffer(body))
	req.Header.Set("Authorization", "Bearer YOUR_APP_API_KEY")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer resp.Body.Close()

	fmt.Println(resp.Status)
}
```

*   *   [How it works](#how-it-works)
    *   [1\. Set up a message](#1-set-up-a-message)
        *   [Personalize your message with liquid](#personalize-your-message-with-liquid)
    *   [2\. Set up your backend to trigger inbox messages](#2-set-up-your-backend-to-trigger-inbox-messages)

Copy page

Copy page [Download .md](/messaging/channels/in-app/inbox/send-inbox-txnl.md)

Is this page helpful?

![](https://docs.customer.io/images/export-success.png) ![](https://docs.customer.io/images/export-failure.png)

# How can we make it better?

Close

Do you need help from Customer.io support?  No  
 Yes

What part of Customer.io do you need help with? 

How can we improve this page?

Email (optional):  Please provide a valid email address

 I am not a bot

 

We appreciate your feedback!

Our support team will contact you as soon as possible
