Formatting API-Triggered Broadcasts
UpdatedWhen you trigger a broadcast, you can send data to personalize your message or override your audience. This page helps you understand the format of that data and how to set up complex recipient groups.
Providing custom data
You’ll send custom data using our API or our libraries. You can also see sample data in our Composer preview.
Here’s a basic example of what some custom data might look like in your request.
{
"data": {
"headline": "Roadrunner spotted in Albuquerque!",
"date": "January 24, 2018",
"text": "We've received reports of a roadrunner in your immediate area! Head to your dashboard to view more information!"
}
}
Overriding Recipients
You can set the audience for an API-triggered broadcast in the UI—which is useful when your audience always meets the same conditions.
But you might want to define a custom audience when you trigger your broadcast. For example, you might send “Breaking News” notifications to different groups of users, but the same content layout. We support a complex set of audience filters, so you can broadcast to a specific group of people. We’ve provided a few basic examples below.
You can nest and
and or
filters`
Nest filters to create complex filters where you have different sets of and
and or
criteria that a person must meet to receive your broadcast.
The “And” filter is an array of objects, where each object represents criteria for your audience. Each object must be true for a person to receive the broadcast. You can nest other compound filters—or
or not
—to set up complex audience conditions.
{
"recipients": {
"and": [
{
"attribute": {
"field": "first_name",
"operator": "exists"
}
},
{
"attribute": {
"field": "likes_baseball",
"operator": "eq",
"value": true
}
}
]
}
}
-
-
- field stringRequired The name of the attribute you want to filter against.
- operator stringRequired Determine how to evaluate criteria against the field—
exists
returns results if a person in the audience has the attribute;eq
returns results if the audience has the attribute and the attribute has thevalue
you specify.Accepted values:
eq
,exists
- value stringThe value you want to match for this attribute. You must include a value if you use the
eq
operator.
- notReturns results if a condition is false. While and/or support an array of items,
not
supports a single filter object.- and array of [ objects ]Match all conditions to return results.
- or array of [ objects ]Returns results matching any conditions.
-
- id integerThe ID of the segment you want to return people from.
-
The “Or” filter is an array of objects where each object represents criteria for your audience. At least one object in the array must be true for a person to receive the broadcast. You can nest other compound filters—and
or not
—to set up complex audience conditions.
{
"recipients": {
"or": [
{
"segment": {
"id": 4
}
},
{
"attribute": {
"field": "likes_baseball",
"operator": "eq",
"value": true
}
}
]
}
}
-
- and array of [ objects ]Returns results matching all conditions.
-
- field stringRequired The name of the attribute you want to filter against.
- operator stringRequired Determine how to evaluate criteria against the field—
exists
returns results if a person in the audience has the attribute;eq
returns results if the audience has the attribute and the attribute has thevalue
you specify.Accepted values:
eq
,exists
- value stringThe value you want to match for this attribute. You must include a value if you use the
eq
operator.
- notReturns results if a condition is false. While and/or support an array of items,
not
supports a single filter object.- and array of [ objects ]Match all conditions to return results.
-
- id integerThe ID of the segment you want to return people from.
A condition that, if true, excludes people from your audience. The not
filter is an object, but can take a complex filter, like and
or or
.
{
"recipients": {
"not": {
"and": [
{
"segment": {
"id": 3
}
},
{
"attribute": {
"field": "likes_baseball",
"operator": "eq",
"value": true
}
}
]
}
}
}
-
- and array of [ objects ]Returns results matching all conditions.
-
- field stringRequired The name of the attribute you want to filter against.
- operator stringRequired Determine how to evaluate criteria against the field—
exists
returns results if a person in the audience has the attribute;eq
returns results if the audience has the attribute and the attribute has thevalue
you specify.Accepted values:
eq
,exists
- value stringThe value you want to match for this attribute. You must include a value if you use the
eq
operator.
- notReturns results if a condition is false. While and/or support an array of items,
not
supports a single filter object.- and array of [ objects ]Match all conditions to return results.
- or array of [ objects ]Returns results matching any conditions.
-
- id integerThe ID of the segment you want to return people from.
A ID of a segment that people must belong to.
{
"recipients": {
"segment": {
"id": 3
}
}
}
- id integerThe ID of the segment you want to return people from.
Filter your audience based on an attribute value. In this case, you’ll provide:
field
: the name of the attributeoperator
: One ofexists
(true if a person has a value) oreq
(true if a person matches avalue
).value
: Required if you use theeq
operator. The value a person’s attribute must equal (eq
) for the condition to be true.
{
"recipients": {
"attribute": {
"field": "likes_baseball",
"operator": "eq",
"value": true
}
}
}
- field stringRequired The name of the attribute you want to filter against.
- operator stringRequired Determine how to evaluate criteria against the field—
exists
returns results if a person in the audience has the attribute;eq
returns results if the audience has the attribute and the attribute has thevalue
you specify.Accepted values:
eq
,exists
- value stringThe value you want to match for this attribute. You must include a value if you use the
eq
operator.
Specify recipients with segments
Find your segment ID You’ll need the numerical ID for each segment you’d like to target. This can be found in the UI by hovering over the segment info icon in the Segment Overview:
Or on the individual segment page:
Then, you can use it to define or override recipients with JSON that looks like this:
{
"data": {
"headline": "Roadrunner spotted in Albuquerque!",
"date": "January 24, 2018",
"text": "We've received reports of a roadrunner in your immediate area! Head to your dashboard to view more information!"
},
"recipients": {
"segment": {
"id": 3
}
}
}
Using multiple segment IDs
Here, you’ll need to format a boolean expression of segment IDs in JSON, like this:
"recipients": {
"or": [
{
"segment": {
"id": 3
}
},
{
"segment": {
"id": 4
}
}
]
}
This would target people who belong to either segment 7 or 8. Use and
if you’d like to target people in both segments.
Specify recipients with attributes
In addition to segment IDs, you can also specify or override recipients with attribute conditions. These accept two operators: eq
and exists
.
Note that you’ll need to separate the operator and value into separate entries!
{
"data": {
"headline": "Roadrunner spotted in Albuquerque!",
"date": "January 24, 2018",
"text": "We've received reports of a roadrunner in your immediate area! Head to your dashboard to view more information!"
},
"recipients": {
"attribute": {
"field": "interest",
"operator": "eq",
"value": "roadrunners"
}
}
}
If you need an is not equal
or does not exist
condition, use the not
operator on an eq/exists attribute condition.. Here is an example with a not
operator:
{
"data": {
"headline": "Roadrunner spotted in Albuquerque!",
"date": "January 24, 2018",
"text": "We've received reports of a roadrunner in your immediate area! Head to your dashboard to view more information!"
},
"recipients": {
"not": {
"attribute": {
"field": "interest",
"operator": "eq",
"value": "roadrunners"
}
}
}
}
Combining segments and attributes
Alternately, you can use a combination of segment and attribute conditions, using the general syntax above. Here’s an example of how to do that, with some simple data to go with it:
{
"data":{
"headline":"Roadrunner spotted in Albuquerque!",
"date":"January 24, 2018",
"text":"We've received reports of a roadrunner in your immediate area! Head to your dashboard to view more information!"
},
"recipients": {
"and": [
{
"segment": {
"id": 3
}
},
{
"or": [
{
"attribute": {
"field": "interest",
"operator": "eq",
"value": "roadrunners"
}
},
{
"attribute": {
"field": "state",
"operator": "eq",
"value": "NM"
}
},
{
"not":{
"attribute": {
"field": "species",
"operator": "eq",
"value": "roadrunners"
}
}
}
]
}
]
}
}
}
Recipient List
In some situations it might be desirable to specify a list of recipients. These can be provided either through a list of profile ids or a list of email addresses.
Profile IDs
The list of profile ids is provided as a JSON array in the attribute ids
.
- You can send up to 10,000
ids
in one API call. Sending more than that will result in an error is returned to the caller. - If any of the profile ids in this array do not correspond to an existing profile’s
id
attribute in Customer.io then the trigger API returns an error to the caller unless the boolean attributeid_ignore_missing
is set to true, in which case the missing ids are ignored. Here’s an example of how to do that, with some simple data to go with it:
{
"data":{
"headline":"Roadrunner spotted in Albuquerque!",
"date":"January 24, 2018",
"text":"We've received reports of a roadrunner in your immediate area! Head to your dashboard to view more information!"
},
"ids": ["wiley", "roadrunner", "acme"],
"id_ignore_missing": true
}
Email Addresses
The list of emails addresses is provided as a JSON array in the attribute emails
.
- You can send up to 10,000
emails
in one API call. Sending more than that will result in an error is returned to the caller. - If any of the email addresses in this array do not correspond to an existing profile’s
email
attribute in Customer.io then the trigger API returns an error to the caller unless the boolean attributeemail_ignore_missing
is set to true, in which case missing emails are ignored. If the data that you are sending contains customers that might not exist in Customer.io application then this is the attribute to use. - If any of the email addresses in this array corresponds to multiple profile ids the trigger API returns an error to the caller unless the boolean attribute
email_add_duplicates
is set to true, in which case all matching customers are added as recipients. Warning: be careful as this means that the same email address will be mailed multiple times.
Here’s an example:
{
"data":{
"headline":"Roadrunner spotted in Albuquerque!",
"date":"January 24, 2018",
"text":"We've received reports of a roadrunner in your immediate area! Head to your dashboard to view more information!"
},
"emails": ["wiley@coyote.com", "road@runner.net", "support@acme.com"],
"email_ignore_missing": true,
"email_add_duplicates": true
}
To see the implication of email_add_duplicates
and email_add_duplicates
, for the sake of an example, let’s assume that your Customer.io account has multiple profiles that have the same value for their email
attribute but different values for their id
attribute.
- If the
email_ignore_missing
is set to true then emails you included that are missing in your Customer.io account will be ignored. - If
email_add_duplicates
is set to true then multiple emails will be sent.
Let’s say you have the following data in your Customer.io account:
id: 1
email: wiley@coyote.com
id: 2
email: wiley@coyote.com
id: 3
email: john@coyote.com
And you send the following JSON data as part of your API call:
{
"data":{
"headline":"Roadrunner spotted in Albuquerque!",
"date":"January 24, 2018",
"text":"We've received reports of a roadrunner in your immediate area! Head to your dashboard to view more information!"
},
"emails": ["wiley@coyote.com", "john@coyote.com", "matt@coyote.com"],
"email_ignore_missing": true,
"email_add_duplicates": true
}
In that case a total of three emails will be sent. Two to wiley@coyote.com and one to john@coyote.com. Whereas matt@coyote.com will be ignored.
Including custom data
If you want to specify a list of recipients but also include custom data for them (for example, a voucher code), you can include a per_user_data
attribute (for up to 10,000 recipients) or a data_file_url
attribute. Custom data included in this way is available in the {{trigger.<attribute_name>}}
space when building your message content, in exactly the same way as data provided in the global data block specified above. If an attribute is specified in both the global block and in the custom block, the value from the custom block will be used for each customer for which it is provided.
- If
per_user_data
ordata_file_url
is specified, the recipients, ids, and emails fields must not be present in the API request. per_user_data
should contain an array of JSON objects where each object contains an identifier (id
oremail
depending on your workspace settings) anddata
values. Below is an example usingper_user_data
.
IMPORTANT: Remove linebreaks and collapse per_user_data
You must collapse/uglify your per_user_data
to prevent errors, as in the example below.
{
"data": {
"headline": "Roadrunner spotted in Albuquerque!",
"date": 1511315635,
"text": "We received reports of a roadrunner in your immediate area! Head to your dashboard to view more information!"
},
"per_user_data":[{"id":"wiley","data":{"voucher_code":"FESwYm"}},{"email":"road@runner.net","data":{"voucher_code":"cYm6XJ"}}]
}
For data_file_url
, the URL provided must be an http or https URL. We recommend using an https server for hosting any files containing sensitive customer information. If the file server requires user/password authentication, the values for those must be provided in the URL, like this: https://user:pass@myserver.com/myfile
. The URL must point at a file that contains one json map per line, with each of those maps being either {"id":xxxx,"data":xxxx}
or {"email":xxxx,"data":xxxx}
. We will download and process the file from the URL, and progress for that process will be visible in the status, with the following new fields:
found_per_user_data
- whether per_user_data was found in the data fileper_user_data_position
- the position to which we have processed (in bytes) in the data fileper_user_data_error_count
- the number of errors recorded so far while processing the data file
Here is an example using data_file_url
:
{
"data": {
"headline": "Roadrunner spotted in Albuquerque!",
"date": 1511315635,
"text": "We received reports of a roadrunner in your immediate area! Head to your dashboard to view more information!"
},
"data_file_url": "https://s3.amazonaws.com/awesometown/upsell_runners.json"
}
and this is what you’d see when checking the status for the trigger:
{
"id": "5-37",
"campaign_id": 5,
"created_at": 1552523326,
"recipients_filter": "{\"segment\":{\"id\":80}}",
"data": "{\n \"headline\": \"Roadrunner spotted in Albuquerque!\",\n \"date\": 1511315635,\n \"text\": \"We received reports of a roadrunner in your immediate area! Head to your dashboard to view more information!\"\n }",
"processed_at": 1552523331,
"recipients_count": 3000,
"workflow_action_ids": [],
'per_user_data_position': 16100,
'found_per_user_data': True,
'per_user_data_error_count': 0
}
If errors are encountered while processing the data file or the values from the per_user_data
block, the GET
API endpoint provides a way to page through the list of errors using the start
and limit
request parameters. If a request returns a non-zero next
attribute, specifying that value as the start
value in the next request will return the next page of errors.
Example:
{
"errors": [
"line 1: couldn't parse json data",
"line 2: couldn't parse json data",
"line 3: couldn't parse json data",
"line 4: couldn't parse json data",
"line 5: couldn't parse json data",
"line 6: couldn't parse json data",
"the following ids are missing: coyottee, crocodile"
],
"next": 0
}
If there are no errors found while processing the file, the broadcast will start automatically as soon as processing of the file has been completed. If the data file or the per_user_data
block may contain ids that are not tracked in Customer.io or emails that don’t correspond to profiles that are tracked in Customer.io, you may specify the id_ignore_missing
or email_ignore_missing
fields in the request to allow the broadcast to ignore the errors and allow the broadcast to continue. The email_add_duplicates
flag may also be used. Once again, be careful with this option, as it means that the same person may receive multiple copies of the broadcast.