API Triggered Broadcasts - Formatting Broadcast Data

API Triggered Broadcasts - Formatting Broadcast Data


Basic data formatting

We ask that you send us your data in JSON format, and recommend that you do so via our API.

Here's a basic example of what some data might look like in JSON format:

{
  "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!"
  }
}


This can then be used as sample data in our Composer preview.

Overriding Recipients

For API Triggered Broadcasts, you can set recipients via the UI.

Defining recipients in the UI

This is useful for when you know your recipients will always need to meet the same condition(s). However, if you're sending many Broadcasts with the same layout but only small differences between them (e.g., "Breaking News!" notifications, each with slightly different groups of users), we offer the option to set your recipient conditions in your API call. Here's how to do that.

KEEP IN MIND:
Recipients set via the API will override what is set in the UI.

General syntax

Here's a condensed version of the formatting we're going to use:

recipients_filter = '"recipients":{'(and|or|not|segment|attribute)'}';
and = '"and":['1*(recipients_filter)']'
or = '"or":['1*(recipients_filter)']'
segment = '"segment":{"id":'number'}'
attribute = '"attribute'":{"field":'string',"operator":'operator',"value":'string|number'}'
operator = '"eq"'|'"exists"'


A few examples follow, to show this syntax in context.

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:

Finding segment ID - segment overview

Or on the individual segment page:

Finding segment ID - individual segment

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": 1
        }
  }
}

Using multiple segment IDs

Here, you'll need to format a boolean expression of segment IDs in JSON, like this:

"recipients": {
  "or": [
    {
      "segment": {
        "id": 7
      }
    },
    {
      "segment": {
        "id": 8
      }
    }
  ]
}

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": 1
        }
      },
      {
        "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 attribute id_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 attribute email_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 or data_file_url is specified, the recipients, ids, and emails fields must not be present in the API request.
  • per_user_datashould contain an array of JSON objects where each object should contain either id and data values, or email and data values. It is allowed to mix id based objects with email based objects.

Here's an example using per_user_data:

{
    "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 file
  • per_user_data_position - the position to which we have processed (in bytes) in the data file
  • per_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.

Was this article helpful?