openapi: 3.2.0 info: version: 1.0.0 title: Customer.io App Send Messages API description: 'Our App API provides ways to trigger messages and retrieve information about people, campaigns, broadcasts, and more. # Overview The App API provides methods to send newsletters, transactional messages, and API-triggered broadcasts. You can create newsletters from scratch and update transactional messages and API-triggered broadcasts. For transactional messages and API-triggered broadcasts, your payload acts as a message "trigger" and can contain `data` that you reference in your messages using liquid—`{{trigger.}}`. The other endpoints help you retrieve information about people, segments, campaigns, broadcasts, etc; it also lets you update campaign actions, messages, newsletter variants, etc. Aside from the [API-triggered broadcast](#triggerBroadcast) (1 per 10 seconds) and [Transactional](#sendEmail) (100 per second) endpoints, requests are limited to 10 per second. # Use our Postman collection We''ve generated a Postman collection to help you get started with our APIs. If you fork this collection, you might want to disable the *Watch original collection* option. We automatically update our Postman collection whenever we release changes to our documentation, even if we don''t change our APIs—which happens daily! Rather than being flooded with Postman notifications, you can check out our [Release Notes](/release-notes/) for updates to our APIs. **NOTE**: Postman endpoints default to our US APIs. If you''re in our European (EU) region, you''ll need to add `-eu` to the server variables (`track_api_url` and `app_api_url`). [Run In Postman](https://god.gw.postman.com/run-collection/23697545-2931c004-e63d-4cdc-bf4b-e685ba6da42d?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D23697545-2931c004-e63d-4cdc-bf4b-e685ba6da42d%26entityType%3Dcollection%26workspaceId%3Db886877f-fc09-475f-84fe-6221a98f4d18#?env%5BCustomer.io%20API%20Environment%5D=W3sia2V5IjoidHJhY2tfYXBpX3VybCIsInR5cGUiOiJkZWZhdWx0IiwidmFsdWUiOiJ0cmFjay5jdXN0b21lci5pbyIsImVuYWJsZWQiOnRydWV9LHsia2V5IjoiYXBwX2FwaV91cmwiLCJ0eXBlIjoiZGVmYXVsdCIsInZhbHVlIjoiYXBpLmN1c3RvbWVyLmlvIiwiZW5hYmxlZCI6dHJ1ZX0seyJrZXkiOiJzaXRlX2lkIiwidHlwZSI6ImRlZmF1bHQiLCJ2YWx1ZSI6IiIsImVuYWJsZWQiOnRydWV9LHsia2V5IjoiYXBpX2tleSIsInR5cGUiOiJzZWNyZXQiLCJ2YWx1ZSI6IiIsImVuYWJsZWQiOnRydWV9LHsia2V5IjoiYmVhcmVyIiwidHlwZSI6ImRlZmF1bHQiLCJ2YWx1ZSI6IiIsImVuYWJsZWQiOnRydWV9LHsia2V5IjoiYnJvYWRjYXN0X2lkIiwidHlwZSI6ImRlZmF1bHQiLCJ2YWx1ZSI6IiIsImVuYWJsZWQiOnRydWV9LHsia2V5IjoiaW1wb3J0X2lkIiwidHlwZSI6ImRlZmF1bHQiLCJ2YWx1ZSI6IiIsImVuYWJsZWQiOnRydWV9LHsia2V5IjoiZW1haWxfYWRkcmVzcyIsInR5cGUiOiJkZWZhdWx0IiwidmFsdWUiOiIiLCJlbmFibGVkIjp0cnVlfSx7ImtleSI6InN1cHByZXNzaW9uX3R5cGUiLCJ0eXBlIjoiZGVmYXVsdCIsInZhbHVlIjoiIiwiZW5hYmxlZCI6dHJ1ZX0seyJrZXkiOiJjb2xsZWN0aW9uX2lkIiwidHlwZSI6ImRlZmF1bHQiLCJ2YWx1ZSI6IiIsImVuYWJsZWQiOnRydWV9LHsia2V5Ijoic25pcHBldF9uYW1lIiwidHlwZSI6ImRlZmF1bHQiLCJ2YWx1ZSI6IiIsImVuYWJsZWQiOnRydWV9LHsia2V5Ijoid2ViaG9va19pZCIsInR5cGUiOiJkZWZhdWx0IiwidmFsdWUiOiIiLCJlbmFibGVkIjp0cnVlfSx7ImtleSI6InNlbmRlcl9pZCIsInR5cGUiOiJkZWZhdWx0IiwidmFsdWUiOiIiLCJlbmFibGVkIjp0cnVlfSx7ImtleSI6ImV4cG9ydF9pZCIsInR5cGUiOiJkZWZhdWx0IiwidmFsdWUiOiIiLCJlbmFibGVkIjp0cnVlfSx7ImtleSI6Im1lc3NhZ2VfaWQiLCJ0eXBlIjoiZGVmYXVsdCIsInZhbHVlIjoiIiwiZW5hYmxlZCI6dHJ1ZX0seyJrZXkiOiJzZWdtZW50X2lkIiwidHlwZSI6ImRlZmF1bHQiLCJ2YWx1ZSI6IiIsImVuYWJsZWQiOnRydWV9LHsia2V5IjoibmV3c2xldHRlcl9pZCIsInR5cGUiOiJkZWZhdWx0IiwidmFsdWUiOiIiLCJlbmFibGVkIjp0cnVlfSx7ImtleSI6ImNvbnRlbnRfaWQiLCJ0eXBlIjoiZGVmYXVsdCIsInZhbHVlIjoiIiwiZW5hYmxlZCI6dHJ1ZX0seyJrZXkiOiJjYW1wYWlnbl9pZCIsInR5cGUiOiJkZWZhdWx0IiwidmFsdWUiOiIiLCJlbmFibGVkIjp0cnVlfSx7ImtleSI6ImFjdGlvbl9pZCIsInR5cGUiOiJkZWZhdWx0IiwidmFsdWUiOiIiLCJlbmFibGVkIjp0cnVlfSx7ImtleSI6ImN1c3RvbWVyX2lkIiwidHlwZSI6ImRlZmF1bHQiLCJ2YWx1ZSI6IiIsImVuYWJsZWQiOnRydWV9LHsia2V5IjoidHJhbnNhY3Rpb25hbF9pZCIsInR5cGUiOiJkZWZhdWx0IiwidmFsdWUiOiIiLCJlbmFibGVkIjp0cnVlfSx7ImtleSI6InRyaWdnZXJfaWQiLCJ0eXBlIjoiZGVmYXVsdCIsInZhbHVlIjoiIiwiZW5hYmxlZCI6dHJ1ZX0seyJrZXkiOiJmb3JtX2lkIiwidHlwZSI6ImRlZmF1bHQiLCJ2YWx1ZSI6IiIsImVuYWJsZWQiOnRydWV9LHsia2V5IjoiaWRlbnRpZmllciIsInR5cGUiOiJkZWZhdWx0IiwidmFsdWUiOiIiLCJlbmFibGVkIjp0cnVlfSx7ImtleSI6ImRldmljZV9pZCIsInR5cGUiOiJkZWZhdWx0IiwidmFsdWUiOiIiLCJlbmFibGVkIjp0cnVlfSx7ImtleSI6ImRlbGl2ZXJ5X2lkIiwidHlwZSI6ImRlZmF1bHQiLCJ2YWx1ZSI6IiIsImVuYWJsZWQiOnRydWV9XQ==) # Server addresses: US and EU Customer.io hosts services in the United States (US) and European Union. Select the appropriate server address for your region. | Region | Server Address | | :-- | :-- | | US | https://api.customer.io | | EU | https://api-eu.customer.io | # Authentication All requests to the Customer.io App API use an [App API Key](#App-API-Key). To authenticate, provide your key as a Bearer token in a HTTP Authorization header. You can create and manage your API keys—including keys with different scopes—in [your account settings page](https://fly.customer.io/settings/api_credentials?keyType=app). Each operation on this page references the authorization header it requires. # Rate Limits Most endpoints on this page are limited to 10 requests per second. The exceptions are: * The [transactional email](#operation/sendEmail) endpoint is limited to 100 requests per second. * The [API-triggered broadcast endpoint](#operation/triggerBroadcast) is limited to 1 request every 10 seconds. **Rate limits are subject to change. We may adjust these thresholds to ensure stable performance for all customers.** ' servers: - url: https://api.customer.io description: The base URL for broadcasts, transactional messages, and data-retrieval APIs. These endpoints use bearer authorization, and require a [token that you generate in the UI](https://fly.customer.io/settings/api_credentials?keyType=app). - url: https://api-eu.customer.io description: The base URL for broadcasts, transactional messages, and data-retrieval APIs (EU region). These endpoints use bearer authorization, and require a [token that you generate in the UI](https://fly.customer.io/settings/api_credentials?keyType=app). tags: - name: Send Messages description: 'Use these endpoints to send broadcasts or transactional messages to your audience. They use the same authentication method, but review the limits for both types of workflows to make sure you''ll successfully trigger your messages. You can''t trigger campaigns through our APIs. ## API triggered broadcast limits While [API triggered broadcasts](#operation/triggerBroadcast) are limited to 1 request every 10 seconds, they''re also limited by the number of triggers you can have queued at a time, as shown in the table below. | Data Type | Limit | Description | | -- | -- | -- | | Trigger Payload | 25MB | Max length of the entire Trigger call, larger calls are typically to support `per_user_data` | | Trigger Data | 50000 bytes | Max length of the data section in the Trigger call | | Recipient List1 | 10000 recipients | Max number of ids or emails included in the Trigger call | | Custom Per User Data1 | 10000 entries | Max number of entries in `per_user_data` | | Custom Per User Data1 | 2MB | Max length per user in the file referenced by `data_file_url`. | | Custom Per User Data1 | 10GB | Max length of the entire size of the file referenced by `data_file_url` | | Trigger Queue | 5 triggers | Max number of triggers waiting to be processed consecutively | 1For larger data sets, use `data_file_url` to supply a link to a file that contains your merge data. Attempting to send too much data in a single API call will fail. ## Transactional Message Limits The `/send-*` endpoints are limited to 100 requests per second. | Data Type | Limit | Description | | -- | -- | -- | | Payload | 1MB | Max length of the payload, excepting attachments | | Attachments (email) | 2MB | Maximum size of attachments | | Recipients | 15 | Total number of recipients across the `to`, `cc`, and `bcc` fields. | ' paths: /v1/campaigns/{broadcast_id}/triggers: servers: - url: https://api.customer.io description: This API uses bearer authorization, requiring a [token that you generate in the UI](https://fly.customer.io/settings/api_credentials?keyType=app). parameters: - name: broadcast_id in: path required: true description: The ID of the broadcast that you want to trigger. schema: type: integer post: operationId: triggerBroadcast tags: - Send Messages summary: Send an API-triggered broadcast security: - Bearer-Auth: [] description: 'Trigger a broadcast (not a newsletter) and optionally provide data to populate liquid placeholders in the message. The shape of the request depends on how you define your audience: default (the recipients set in the UI), custom filter conditions, a list of emails, a list of customer IDs, a map of users, or a data file. **You can only trigger broadcasts to send to people you''ve already added to your workspace.** A broadcast cannot add or identify new people. If you reference people who don''t exist in your broadcast audience, the broadcast will fail by default. You can override this behavior by setting the `email_ignore_missing` and/or `id_ignore_missing` flags to `true`. The broadcast will skip over any people who don''t exist in your workspace and send to the remaining recipients. You can reference properties in the `data` object in your broadcast using liquid—`{{trigger.}}`. If your broadcast produces a `422` error, you can [get more information about the errors](#tag/broadcasts/broadcastErrors) to see what went wrong. **This endpoint is rate-limited to one request every 10 seconds.** After exceeding this, you''ll receive a status of `429`. Learn more about [API-triggered broadcast limits](/integrations/api/app/#tag/send-messages) above. Broadcasts are optimized to send messages to a large audience and not for one-to-one interactions. Use our [transactional API](#tag/send-messages/sendEmail) or [event-triggered campaigns](/journeys/send/campaigns/triggers/#event-trigger) to respond to your audience on an individual, one-to-one basis. ' requestBody: content: application/json: x-rate-limit: 10 schema: x-scalar-ignore: true oneOf: - title: Default audience description: Send your broadcast to the default set of recipients defined in the UI. allOf: - x-scalar-ignore: true type: object properties: data: type: object description: Contains information you want to use to populate your broadcast. additionalProperties: x-additionalPropertiesName: Broadcast liquid data description: Insert key-values that you want to reference in your message here. example: 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! email_add_duplicates: type: boolean default: false description: an email address associated with more than one profile id is an error. email_ignore_missing: type: boolean default: false description: If false, a missing email causes the broadcast to error and fail. If true, the broadcast will skip over any people in your audience who don't have emails, and continue sending to the rest of your audience. id_ignore_missing: type: boolean default: false description: If false, a missing customer ID causes the broadcast to error and fail. If true, the broadcast will skip over any people in your audience who don't have IDs, and continue sending to the rest of your audience. - title: Custom recipients description: Send your broadcast to a group of people defined by a set of filters. allOf: - type: object required: - recipients properties: recipients: x-scalar-ignore: true title: Audience Filter description: Use `and`, `or`, and `not` to combine segment and attribute conditions. The top-level object accepts one property; nest groups for complex filters. oneOf: - x-scalar-ignore: true title: and type: object properties: and: type: array description: Match *all* conditions to return results. items: type: object properties: or: type: array description: Returns results matching *any* conditions. items: x-scalar-ignore: true anyOf: - title: segment description: Filter for people who belong to a segment. type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: audience type: object description: filter for people who have an attribute or an attribute value. properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true not: description: Returns results if a condition is false. While and/or support an array of items, `not` supports a single filter object. oneOf: - title: and type: object properties: and: type: array description: Match *all* conditions to return results. items: x-scalar-ignore: true anyOf: - title: segment description: Filter for people who belong to a segment. type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: audience type: object description: filter for people who have an attribute or an attribute value. properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true - title: or type: object properties: or: type: array description: Match *any* condition to return results. items: x-scalar-ignore: true anyOf: - title: segment description: Filter for people who belong to a segment. type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: audience type: object description: filter for people who have an attribute or an attribute value. properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true - title: segment type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: attribute type: object properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true - x-scalar-ignore: true title: or type: object properties: or: type: array description: Match *any* condition to return results. items: type: object properties: and: type: array description: Returns results matching *all* conditions. items: x-scalar-ignore: true anyOf: - title: segment description: Filter for people who belong to a segment. type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: audience type: object description: filter for people who have an attribute or an attribute value. properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true not: description: Returns results if a condition is false. While and/or support an array of items, `not` supports a single filter object. oneOf: - title: and type: object properties: and: type: array description: Match *all* conditions to return results. items: x-scalar-ignore: true anyOf: - title: segment description: Filter for people who belong to a segment. type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: audience type: object description: filter for people who have an attribute or an attribute value. properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true - title: or type: object properties: or: type: array description: Match *any* condition to return results. items: x-scalar-ignore: true anyOf: - title: segment description: Filter for people who belong to a segment. type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: audience type: object description: filter for people who have an attribute or an attribute value. properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true - title: segment type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: attribute type: object properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true - x-scalar-ignore: true title: not description: Returns results if a condition is false. While and/or support an array of items, `not` supports a single filter object. oneOf: - title: and type: object properties: and: type: array description: Match *all* conditions to return results. items: x-scalar-ignore: true title: People Filter type: object description: Filter people with `and`, `or`, and `not` groups made from `segment` and `attribute` conditions. properties: and: type: array description: Returns results matching *all* conditions. items: x-scalar-ignore: true anyOf: - title: segment description: Filter for people who belong to a segment. type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: audience type: object description: filter for people who have an attribute or an attribute value. properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true or: type: array description: Returns results matching *any* conditions. items: x-scalar-ignore: true anyOf: - title: segment description: Filter for people who belong to a segment. type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: audience type: object description: filter for people who have an attribute or an attribute value. properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true not: description: Returns results if a condition is false. While and/or support an array of items, `not` supports a single filter object. oneOf: - title: and type: object properties: and: type: array description: Match *all* conditions to return results. items: x-scalar-ignore: true anyOf: - title: segment description: Filter for people who belong to a segment. type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: audience type: object description: filter for people who have an attribute or an attribute value. properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true - title: or type: object properties: or: type: array description: Match *any* condition to return results. items: x-scalar-ignore: true anyOf: - title: segment description: Filter for people who belong to a segment. type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: audience type: object description: filter for people who have an attribute or an attribute value. properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true - title: segment type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: attribute type: object properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true - title: or type: object properties: or: type: array description: Match *any* condition to return results. items: x-scalar-ignore: true title: People Filter type: object description: Filter people with `and`, `or`, and `not` groups made from `segment` and `attribute` conditions. properties: and: type: array description: Returns results matching *all* conditions. items: x-scalar-ignore: true anyOf: - title: segment description: Filter for people who belong to a segment. type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: audience type: object description: filter for people who have an attribute or an attribute value. properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true or: type: array description: Returns results matching *any* conditions. items: x-scalar-ignore: true anyOf: - title: segment description: Filter for people who belong to a segment. type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: audience type: object description: filter for people who have an attribute or an attribute value. properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true not: description: Returns results if a condition is false. While and/or support an array of items, `not` supports a single filter object. oneOf: - title: and type: object properties: and: type: array description: Match *all* conditions to return results. items: x-scalar-ignore: true anyOf: - title: segment description: Filter for people who belong to a segment. type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: audience type: object description: filter for people who have an attribute or an attribute value. properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true - title: or type: object properties: or: type: array description: Match *any* condition to return results. items: x-scalar-ignore: true anyOf: - title: segment description: Filter for people who belong to a segment. type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: audience type: object description: filter for people who have an attribute or an attribute value. properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true - title: segment type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: attribute type: object properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true - title: segment type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: attribute type: object properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true - title: segment description: Filter for people who belong to a segment. type: object properties: segment: x-scalar-ignore: true title: segment type: object description: Provide the `id` of a segment containing people you want to search for. properties: id: type: integer description: The ID of the segment you want to return people from. example: 4 - title: audience type: object description: filter for people who have an attribute or an attribute value. properties: attribute: x-scalar-ignore: true title: attribute description: Filter your audience by attribute. type: object required: - field - operator properties: field: type: string description: The name of the attribute you want to filter against. example: first_name operator: type: string description: 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 the `value` you specify. enum: - eq - exists value: type: string description: The value you want to match for this attribute. You must include a value if you use the `eq` operator. example: field: unsubscribed operator: eq value: true - x-scalar-ignore: true type: object properties: data: type: object description: Contains information you want to use to populate your broadcast. additionalProperties: x-additionalPropertiesName: Broadcast liquid data description: Insert key-values that you want to reference in your message here. example: 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! email_add_duplicates: type: boolean default: false description: an email address associated with more than one profile id is an error. email_ignore_missing: type: boolean default: false description: If false, a missing email causes the broadcast to error and fail. If true, the broadcast will skip over any people in your audience who don't have emails, and continue sending to the rest of your audience. id_ignore_missing: type: boolean default: false description: If false, a missing customer ID causes the broadcast to error and fail. If true, the broadcast will skip over any people in your audience who don't have IDs, and continue sending to the rest of your audience. example: 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 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! - title: Emails description: An array of emails you want to send the broadcast to. These addresses must already exist; your request cannot create a new person. allOf: - type: object required: - emails properties: emails: description: An array of email addresses you want to send the broadcast to. These addresses must already exist; your request cannot create a new person. type: array items: type: string format: email example: - recipient1@example.com - anotherRecipient@example.com - x-scalar-ignore: true type: object properties: data: type: object description: Contains information you want to use to populate your broadcast. additionalProperties: x-additionalPropertiesName: Broadcast liquid data description: Insert key-values that you want to reference in your message here. example: 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! email_add_duplicates: type: boolean default: false description: an email address associated with more than one profile id is an error. email_ignore_missing: type: boolean default: false description: If false, a missing email causes the broadcast to error and fail. If true, the broadcast will skip over any people in your audience who don't have emails, and continue sending to the rest of your audience. id_ignore_missing: type: boolean default: false description: If false, a missing customer ID causes the broadcast to error and fail. If true, the broadcast will skip over any people in your audience who don't have IDs, and continue sending to the rest of your audience. - title: IDs description: An array of customer ids that you want to send the broadcast to. These IDs must already exist; your request cannot create a new person. allOf: - type: object required: - ids properties: ids: description: 'An array of IDs you want to send a broadcast to. **NOTE**: If your workspace identifies people by `email`, don''t use this option. Identify your audience by `emails` instead. ' type: array maxItems: 10000 items: type: string example: - id1 - id4 - x-scalar-ignore: true type: object properties: data: type: object description: Contains information you want to use to populate your broadcast. additionalProperties: x-additionalPropertiesName: Broadcast liquid data description: Insert key-values that you want to reference in your message here. example: 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! email_add_duplicates: type: boolean default: false description: an email address associated with more than one profile id is an error. email_ignore_missing: type: boolean default: false description: If false, a missing email causes the broadcast to error and fail. If true, the broadcast will skip over any people in your audience who don't have emails, and continue sending to the rest of your audience. id_ignore_missing: type: boolean default: false description: If false, a missing customer ID causes the broadcast to error and fail. If true, the broadcast will skip over any people in your audience who don't have IDs, and continue sending to the rest of your audience. - title: User Maps description: An array of JSON objects containing `id` or `email` keys and a `data` key. Each object represents a person you want to send the broadcast to and data you want to personalize their message with using liquid. allOf: - type: object required: - per_user_data properties: per_user_data: description: The people you want to send a broadcast to, with custom data to personalize each message. Each person must already exist in your workspace—a broadcast trigger can't create people. type: array maxItems: 10000 items: oneOf: - title: ids type: object required: - id properties: id: type: string description: The ID of the recipient. example: 1 data: type: object description: Merge data associated with the recipient. additionalProperties: x-additionalPropertiesName: Liquid merge data description: Insert key-values that you want to reference in your message here. example: firstName: Hugh lastName: Mann purchase: shoes - title: emails type: object required: - email properties: email: type: string description: The email address of the recipient. This address must be unique in your workspace. If more than one person has the same `email` attribute, your request will produce an error. example: recipient1@example.com data: description: Merge data associated with the recipient. type: object additionalProperties: x-additionalPropertiesName: Liquid merge data description: Insert key-values that you want to reference in your message here. example: firstName: Hugh lastName: Mann purchase: shoes example: - id: wiley_coyote data: voucher_code: FESwYm - email: road@runner.net data: voucher_code: cYm6XJ - x-scalar-ignore: true type: object properties: data: type: object description: Contains information you want to use to populate your broadcast. additionalProperties: x-additionalPropertiesName: Broadcast liquid data description: Insert key-values that you want to reference in your message here. example: 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! email_add_duplicates: type: boolean default: false description: an email address associated with more than one profile id is an error. email_ignore_missing: type: boolean default: false description: If false, a missing email causes the broadcast to error and fail. If true, the broadcast will skip over any people in your audience who don't have emails, and continue sending to the rest of your audience. id_ignore_missing: type: boolean default: false description: If false, a missing customer ID causes the broadcast to error and fail. If true, the broadcast will skip over any people in your audience who don't have IDs, and continue sending to the rest of your audience. - title: Data file URL description: The URL of a data file with one JSON object per line, using either `id` and `data` or `email` and `data`. The people you reference must already exist in your workspace. The file may be gzip-compressed to reduce transfer size (recommended for large files); if compressed, it must use gzip and the hosting server must return a `Content-Encoding` header set to `gzip` when the file is downloaded. allOf: - type: object required: - data_file_url properties: data_file_url: description: The URL of a JSON Lines file with one person per line, using `id` and `data` or `email` and `data`. The people you reference must already exist in your workspace. The file may be gzip-compressed to reduce transfer size (recommended for large files); if compressed, it must use gzip and the hosting server must return a `Content-Encoding` header set to `gzip` when the file is downloaded. type: string format: url example: https://myFile.example.com - x-scalar-ignore: true type: object properties: data: type: object description: Contains information you want to use to populate your broadcast. additionalProperties: x-additionalPropertiesName: Broadcast liquid data description: Insert key-values that you want to reference in your message here. example: 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! email_add_duplicates: type: boolean default: false description: an email address associated with more than one profile id is an error. email_ignore_missing: type: boolean default: false description: If false, a missing email causes the broadcast to error and fail. If true, the broadcast will skip over any people in your audience who don't have emails, and continue sending to the rest of your audience. id_ignore_missing: type: boolean default: false description: If false, a missing customer ID causes the broadcast to error and fail. If true, the broadcast will skip over any people in your audience who don't have IDs, and continue sending to the rest of your audience. responses: '200': description: A successful request returns the trigger ID. content: application/json: schema: type: object properties: id: type: integer description: The `trigger_id` for this operation. You can use this ID to get the status of your broadcast or [check for errors](#operation/broadcastErrors). example: 3 '401': description: Unauthorized request. Make sure that you provided the right credentials. '404': description: The `broadcast_id` does not exist. '422': description: The broadcast has one or more validation errors. You can learn more by [checking your broadcast for errors](#operation/broadcastErrors) using the `trigger_id` found in the error `detail`. content: application/json: schema: type: object properties: errors: description: Contains one or more validation errors found in your request payload. type: array items: type: object properties: detail: type: string description: Describes the error and provides the trigger ID you can use to look up more information. example: Errors were found while processing per user data (ids, emails or json data). More detail available from the errors endpoint for trigger 12" source: type: object properties: pointer: type: string description: Points to the key in your payload that contained validation errors. example: /data/attributes/per_user_data status: type: string description: The error code. enum: - '422' example: '422' x-codeSamples: - lang: json label: JSON source: '{}' - label: Node.js (SDK) lang: javascript source: "const { APIClient, RegionUS } = require('customerio-node');\nconst api = new APIClient('bearer-app-key', { region: RegionUS });\n\nconst data = {\n headline: 'Roadrunner spotted in Albuquerque!',\n date: 1511315635,\n text:\n \"We've received reports of a roadrunner in your immediate area! Head to your dashboard to view more information!\",\n};\n\napi.triggerBroadcast(campaignId, data, { segment: { id: 7 } });\n" - lang: Shell + Curl source: "curl --request POST \\\n --header 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n --url https://api.customer.io/v1/campaigns/{broadcast_id}/triggers \\\n --header 'content-type: application/json' \\\n --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!\"},\"email_add_duplicates\":false,\"email_ignore_missing\":false,\"id_ignore_missing\":false}'" - lang: Node + Native source: "const http = require(\"https\");\n\nconst options = {\n \"method\": \"POST\",\n \"hostname\": \"api.customer.io\",\n \"port\": null,\n \"path\": \"/v1/campaigns/%7Bbroadcast_id%7D/triggers\",\n \"headers\": {\n \"content-type\": \"application/json\"\n }\n};\n\nconst req = http.request(options, function (res) {\n const chunks = [];\n\n res.on(\"data\", function (chunk) {\n chunks.push(chunk);\n });\n\n res.on(\"end\", function () {\n const body = Buffer.concat(chunks);\n console.log(body.toString());\n });\n});\n\nreq.write(JSON.stringify({\n 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 },\n email_add_duplicates: false,\n email_ignore_missing: false,\n id_ignore_missing: false\n}));\nreq.end();" - lang: Ruby + Native source: 'require ''uri'' require ''net/http'' require ''openssl'' url = URI("https://api.customer.io/v1/campaigns/%7Bbroadcast_id%7D/triggers") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Post.new(url) request["content-type"] = ''application/json'' request.body = "{\"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!\"},\"email_add_duplicates\":false,\"email_ignore_missing\":false,\"id_ignore_missing\":false}" response = http.request(request) puts response.read_body' - lang: Python + Python3 source: 'import http.client conn = http.client.HTTPSConnection("api.customer.io") payload = "{\"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!\"},\"email_add_duplicates\":false,\"email_ignore_missing\":false,\"id_ignore_missing\":false}" headers = { ''content-type'': "application/json" } conn.request("POST", "/v1/campaigns/%7Bbroadcast_id%7D/triggers", payload, headers) res = conn.getresponse() data = res.read() print(data.decode("utf-8"))' - lang: Go + Native source: "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\n\turl := \"https://api.customer.io/v1/campaigns/%7Bbroadcast_id%7D/triggers\"\n\n\tpayload := strings.NewReader(\"{\\\"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!\\\"},\\\"email_add_duplicates\\\":false,\\\"email_ignore_missing\\\":false,\\\"id_ignore_missing\\\":false}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"content-type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" /v1/newsletters/{newsletter_id}/send: servers: - url: https://api.customer.io description: This API uses bearer authorization, requiring a [token that you generate in the UI](https://fly.customer.io/settings/api_credentials?keyType=app). parameters: - name: newsletter_id in: path required: true description: The identifier of a newsletter. schema: type: integer post: operationId: sendNewsletter tags: - Send Messages summary: Send a newsletter security: - Bearer-Auth: [] description: 'Send a newsletter immediately. The newsletter must be in a draft state. If the newsletter has already been sent, you''ll get a `400` error. The recipients for the newsletter are defined when you create/update the newsletter. If you''re not sure who will receive the newsletter, you can use the [List newsletters](/integrations/api/app/#tag/newsletters/listNewsletters) endpoint to get a list of newsletters and their recipients. To reschedule a newsletter, use the [Schedule a newsletter](#tag/send-messages/scheduleNewsletter) endpoint instead. ' requestBody: required: false content: application/json: schema: type: object example: rate_limit_email_rate: 500 rate_limit_time_period: 60 rate_limit_spread: true description: Optional newsletter rate limiting. If you set `rate_limit_email_rate` or `rate_limit_time_period`, set both; `rate_limit_spread` can be set alone. properties: rate_limit_email_rate: type: integer minimum: 1 description: 'Maximum number of messages per time period. **NOTE:** Though this states `email_rate`, you can use this for other message channels. Only fixed rate limits are supported, not [daily ramp limits](/journeys/send/broadcasts/newsletters/#daily-ramp). ' rate_limit_time_period: type: integer enum: - 60 - 3600 - 86400 description: Time period in seconds for rate limiting. Must be one of 60 (minute), 3600 (hour), or 86400 (day). rate_limit_spread: type: boolean description: When `true`, spreads messages evenly across the time period. Otherwise, it sends as fast as possible up to the limit in each period. examples: rateLimited: value: rate_limit_email_rate: 1000 rate_limit_time_period: 3600 rate_limit_spread: true responses: '200': description: The newsletter is queued. content: application/json: schema: type: object properties: newsletter: x-scalar-ignore: true type: object properties: id: x-scalar-ignore: true description: The identifier for a newsletter. type: integer example: 10 deduplicate_id: x-scalar-ignore: true type: string readOnly: true description: An identifier in the format `id:timestamp` where the id is for the object you're working with (Campaigns, Deliveries, Exports, Identities, Newsletters, Segments, and Templates), and the timestamp is the last time the object was updated. example: 15:1492548073 content_ids: type: array description: A list of message variants in a newsletter, where a variant is a translation or A/B test. items: type: integer name: type: string description: The name of the newsletter. Must be 190 characters or less. readOnly: true sent_at: type: integer format: unix timestamp description: The last time the newsletter was sent. created: x-scalar-ignore: true type: integer format: unix timestamp description: The date time when the referenced ID was created. example: 1552341937 readOnly: true updated: x-scalar-ignore: true type: integer format: unix timestamp description: The date time when the referenced ID was last updated. example: 1552341937 readOnly: true type: x-scalar-ignore: true description: Channel type for a newsletter or newsletter content variant. type: string enum: - email - webhook - twilio - push - in_app - inbox readOnly: true example: email tags: type: array description: An array of tags associated with the newsletter. items: type: string recipient_segment_ids: description: If the recipient conditions included segments, this returns a list of those segment ids. type: array items: type: integer subscription_topic_id: type: integer description: If you enabled a [subscription center](/journeys/channels/subscriptions/center/) on your workspace, this returns the id of the subscription preference you set. example: id: 128275 deduplicate_id: 128275:1484870424 type: email content_ids: - 45 name: Weekly Product Update sent_at: 1481653929 created: 1481653919 updated: 1481653929 recipient_segment_ids: - 42 - 99 tags: - Product Updates subscription_topic_id: 5 '400': description: 'The request is invalid. Possible reasons include: - The newsletter has already been sent - The newsletter doesn''t have a valid channel set - No recipients have been configured - Segments are still processing ' content: application/json: schema: x-scalar-ignore: true type: object description: Error response format for newsletter endpoints. properties: errors: type: array items: type: object properties: detail: type: string description: A message describing the error. example: errors: - detail: subscription_topic_id is required '404': description: The newsletter does not exist. '422': description: 'Validation error. The rate limit configuration is incomplete—if you provide `rate_limit_email_rate`, you must also provide `rate_limit_time_period` (and vice versa). ' content: application/json: schema: x-scalar-ignore: true type: object description: Error response format for newsletter endpoints. properties: errors: type: array items: type: object properties: detail: type: string description: A message describing the error. example: errors: - detail: subscription_topic_id is required '429': description: Your request is over the 10-per-second limit. x-codeSamples: - lang: json label: JSON source: "{\n \"rate_limit_email_rate\": 500,\n \"rate_limit_time_period\": 60,\n \"rate_limit_spread\": true\n}" - lang: Shell + Curl source: "curl --request POST \\\n --header 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n --url https://api.customer.io/v1/newsletters/{newsletter_id}/send \\\n --header 'content-type: application/json' \\\n --data '{\"rate_limit_email_rate\":500,\"rate_limit_time_period\":60,\"rate_limit_spread\":true}'" - lang: Node + Native source: "const http = require(\"https\");\n\nconst options = {\n \"method\": \"POST\",\n \"hostname\": \"api.customer.io\",\n \"port\": null,\n \"path\": \"/v1/newsletters/%7Bnewsletter_id%7D/send\",\n \"headers\": {\n \"content-type\": \"application/json\"\n }\n};\n\nconst req = http.request(options, function (res) {\n const chunks = [];\n\n res.on(\"data\", function (chunk) {\n chunks.push(chunk);\n });\n\n res.on(\"end\", function () {\n const body = Buffer.concat(chunks);\n console.log(body.toString());\n });\n});\n\nreq.write(JSON.stringify({\n rate_limit_email_rate: 500,\n rate_limit_time_period: 60,\n rate_limit_spread: true\n}));\nreq.end();" - lang: Ruby + Native source: 'require ''uri'' require ''net/http'' require ''openssl'' url = URI("https://api.customer.io/v1/newsletters/%7Bnewsletter_id%7D/send") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Post.new(url) request["content-type"] = ''application/json'' request.body = "{\"rate_limit_email_rate\":500,\"rate_limit_time_period\":60,\"rate_limit_spread\":true}" response = http.request(request) puts response.read_body' - lang: Python + Python3 source: 'import http.client conn = http.client.HTTPSConnection("api.customer.io") payload = "{\"rate_limit_email_rate\":500,\"rate_limit_time_period\":60,\"rate_limit_spread\":true}" headers = { ''content-type'': "application/json" } conn.request("POST", "/v1/newsletters/%7Bnewsletter_id%7D/send", payload, headers) res = conn.getresponse() data = res.read() print(data.decode("utf-8"))' - lang: Go + Native source: "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\n\turl := \"https://api.customer.io/v1/newsletters/%7Bnewsletter_id%7D/send\"\n\n\tpayload := strings.NewReader(\"{\\\"rate_limit_email_rate\\\":500,\\\"rate_limit_time_period\\\":60,\\\"rate_limit_spread\\\":true}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"content-type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" /v1/newsletters/{newsletter_id}/schedule: servers: - url: https://api.customer.io description: This API uses bearer authorization, requiring a [token that you generate in the UI](https://fly.customer.io/settings/api_credentials?keyType=app). parameters: - name: newsletter_id in: path required: true description: The identifier of a newsletter. schema: type: integer post: operationId: scheduleNewsletter tags: - Send Messages summary: Schedule a newsletter security: - Bearer-Auth: [] description: 'Schedule a newsletter to send at a specific time. The newsletter must be in a draft state. If the newsletter has already been sent, you''ll get a `400` error. If the newsletter is already scheduled, this endpoint updates the scheduled time. The recipients for the newsletter are defined when you create/update the newsletter. If you''re not sure who will receive the newsletter, you can use the [List newsletters](/integrations/api/app/#tag/newsletters/listNewsletters) endpoint to get a list of newsletters and their recipients. ' requestBody: required: true content: application/json: schema: type: object example: scheduled_at: 1719849600 timezone: America/New_York tz_match_enabled: false rate_limit_email_rate: 500 rate_limit_time_period: 60 rate_limit_spread: true allOf: - type: object required: - scheduled_at properties: scheduled_at: type: integer format: unix timestamp description: 'Unix timestamp for the send. Use `0` to deschedule. When greater than `0`, the time must be in the future and you must send `timezone` so the UI displays the time correctly. ' timezone: type: string description: '[IANA timezone name](/journeys/send/timezones/example-timezones/#region-format) (for example, `America/New_York`). Required when `scheduled_at` is greater than `0`. Not required when descheduling (`scheduled_at` is `0`). ' tz_match_enabled: type: boolean description: When `true`, sends at the same local time in each recipient's timezone. If it's set to `true` and `rate_limit_time_period` is provided, then the period can't be greater than `3600` (1 hour). - type: object example: rate_limit_email_rate: 500 rate_limit_time_period: 60 rate_limit_spread: true description: Optional newsletter rate limiting. If you set `rate_limit_email_rate` or `rate_limit_time_period`, set both; `rate_limit_spread` can be set alone. properties: rate_limit_email_rate: type: integer minimum: 1 description: 'Maximum number of messages per time period. **NOTE:** Though this states `email_rate`, you can use this for other message channels. Only fixed rate limits are supported, not [daily ramp limits](/journeys/send/broadcasts/newsletters/#daily-ramp). ' rate_limit_time_period: type: integer enum: - 60 - 3600 - 86400 description: Time period in seconds for rate limiting. Must be one of 60 (minute), 3600 (hour), or 86400 (day). rate_limit_spread: type: boolean description: When `true`, spreads messages evenly across the time period. Otherwise, it sends as fast as possible up to the limit in each period. responses: '200': description: The newsletter is scheduled for sending. content: application/json: schema: type: object properties: newsletter: x-scalar-ignore: true type: object properties: id: x-scalar-ignore: true description: The identifier for a newsletter. type: integer example: 10 deduplicate_id: x-scalar-ignore: true type: string readOnly: true description: An identifier in the format `id:timestamp` where the id is for the object you're working with (Campaigns, Deliveries, Exports, Identities, Newsletters, Segments, and Templates), and the timestamp is the last time the object was updated. example: 15:1492548073 content_ids: type: array description: A list of message variants in a newsletter, where a variant is a translation or A/B test. items: type: integer name: type: string description: The name of the newsletter. Must be 190 characters or less. readOnly: true sent_at: type: integer format: unix timestamp description: The last time the newsletter was sent. created: x-scalar-ignore: true type: integer format: unix timestamp description: The date time when the referenced ID was created. example: 1552341937 readOnly: true updated: x-scalar-ignore: true type: integer format: unix timestamp description: The date time when the referenced ID was last updated. example: 1552341937 readOnly: true type: x-scalar-ignore: true description: Channel type for a newsletter or newsletter content variant. type: string enum: - email - webhook - twilio - push - in_app - inbox readOnly: true example: email tags: type: array description: An array of tags associated with the newsletter. items: type: string recipient_segment_ids: description: If the recipient conditions included segments, this returns a list of those segment ids. type: array items: type: integer subscription_topic_id: type: integer description: If you enabled a [subscription center](/journeys/channels/subscriptions/center/) on your workspace, this returns the id of the subscription preference you set. example: id: 128275 deduplicate_id: 128275:1484870424 type: email content_ids: - 45 name: Weekly Product Update sent_at: 1481653929 created: 1481653919 updated: 1481653929 recipient_segment_ids: - 42 - 99 tags: - Product Updates subscription_topic_id: 5 example: newsletter: id: 128275 deduplicate_id: 128275:1484870424 type: email content_ids: - 45 name: Weekly Product Update sent_at: null created: 1481653919 updated: 1481653929 recipient_segment_ids: - 42 - 99 subscription_topic_id: 5 '400': description: 'The request is invalid. Possible reasons include: - The newsletter has already been sent - The newsletter doesn''t have a valid channel set - No recipients have been configured - The newsletter is not currently scheduled (when descheduling with `scheduled_at: 0`) ' content: application/json: schema: x-scalar-ignore: true type: object description: Error response format for newsletter endpoints. properties: errors: type: array items: type: object properties: detail: type: string description: A message describing the error. example: errors: - detail: subscription_topic_id is required '404': description: The newsletter does not exist. '422': description: 'Validation error. Possible reasons include: - `scheduled_at` is required - `scheduled_at` must be in the future - `timezone` is required (when `scheduled_at` is set) - Unknown timezone value - Incomplete rate limit—both `rate_limit_email_rate` and `rate_limit_time_period` are required when setting a rate limit - Cannot set rate limit periods longer than one hour when sending in the recipient''s timezone (`tz_match`) ' content: application/json: schema: x-scalar-ignore: true type: object description: Error response format for newsletter endpoints. properties: errors: type: array items: type: object properties: detail: type: string description: A message describing the error. example: errors: - detail: subscription_topic_id is required '429': description: Your request is over the 10-per-second limit. x-codeSamples: - lang: json label: JSON source: "{\n \"scheduled_at\": 1719849600,\n \"timezone\": \"America/New_York\",\n \"tz_match_enabled\": false,\n \"rate_limit_email_rate\": 500,\n \"rate_limit_time_period\": 60,\n \"rate_limit_spread\": true\n}" - lang: Shell + Curl source: "curl --request POST \\\n --header 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n --url https://api.customer.io/v1/newsletters/{newsletter_id}/schedule \\\n --header 'content-type: application/json' \\\n --data '{\"scheduled_at\":1719849600,\"timezone\":\"America/New_York\",\"tz_match_enabled\":false,\"rate_limit_email_rate\":500,\"rate_limit_time_period\":60,\"rate_limit_spread\":true}'" - lang: Node + Native source: "const http = require(\"https\");\n\nconst options = {\n \"method\": \"POST\",\n \"hostname\": \"api.customer.io\",\n \"port\": null,\n \"path\": \"/v1/newsletters/%7Bnewsletter_id%7D/schedule\",\n \"headers\": {\n \"content-type\": \"application/json\"\n }\n};\n\nconst req = http.request(options, function (res) {\n const chunks = [];\n\n res.on(\"data\", function (chunk) {\n chunks.push(chunk);\n });\n\n res.on(\"end\", function () {\n const body = Buffer.concat(chunks);\n console.log(body.toString());\n });\n});\n\nreq.write(JSON.stringify({\n scheduled_at: 1719849600,\n timezone: 'America/New_York',\n tz_match_enabled: false,\n rate_limit_email_rate: 500,\n rate_limit_time_period: 60,\n rate_limit_spread: true\n}));\nreq.end();" - lang: Ruby + Native source: 'require ''uri'' require ''net/http'' require ''openssl'' url = URI("https://api.customer.io/v1/newsletters/%7Bnewsletter_id%7D/schedule") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Post.new(url) request["content-type"] = ''application/json'' request.body = "{\"scheduled_at\":1719849600,\"timezone\":\"America/New_York\",\"tz_match_enabled\":false,\"rate_limit_email_rate\":500,\"rate_limit_time_period\":60,\"rate_limit_spread\":true}" response = http.request(request) puts response.read_body' - lang: Python + Python3 source: 'import http.client conn = http.client.HTTPSConnection("api.customer.io") payload = "{\"scheduled_at\":1719849600,\"timezone\":\"America/New_York\",\"tz_match_enabled\":false,\"rate_limit_email_rate\":500,\"rate_limit_time_period\":60,\"rate_limit_spread\":true}" headers = { ''content-type'': "application/json" } conn.request("POST", "/v1/newsletters/%7Bnewsletter_id%7D/schedule", payload, headers) res = conn.getresponse() data = res.read() print(data.decode("utf-8"))' - lang: Go + Native source: "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\n\turl := \"https://api.customer.io/v1/newsletters/%7Bnewsletter_id%7D/schedule\"\n\n\tpayload := strings.NewReader(\"{\\\"scheduled_at\\\":1719849600,\\\"timezone\\\":\\\"America/New_York\\\",\\\"tz_match_enabled\\\":false,\\\"rate_limit_email_rate\\\":500,\\\"rate_limit_time_period\\\":60,\\\"rate_limit_spread\\\":true}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"content-type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" /v1/send/email: servers: - url: https://api.customer.io description: This API uses bearer authorization, requiring a [token that you generate in the UI](https://fly.customer.io/settings/api_credentials?keyType=app). post: summary: Send a transactional email operationId: sendEmail security: - Bearer-Auth: [] - ServiceAccount-Auth: [] description: 'Send a transactional email. While not strictly required, we recommend that you include a `transactional_message_id` in your request. If you don''t, Customer.io attributes metrics to `"transactional_message_id": 1`, so multiple messages can roll up under the same ID. If this is the first time you send a message with the API, you can include the `auto_create` parameter along with a `transactional_message_id` string to create a record for you. You can also include a `body`, `subject`, and `from` values to override the message template. Or, if you create your message entirely through the API, you *must* include these values because your `transactional_message_id` won''t have any content. See [Examples and API parameters](/journeys/send/transactional/email/#auto-create-transactional-message-records) for more details. ' tags: - Send Messages parameters: - x-scalar-ignore: true name: X-Workspace-Id in: header required: false description: 'The numeric ID of the workspace you want to send a message in. This header is only needed when you authenticate with a service-account bearer token (`sa_live_…`). Service accounts work across workspaces, so you must supply this header so we know which workspace to send from. You can omit this header when you authenticate with a standard App API key, which is always scoped to one workspace. ' schema: type: integer example: 100 requestBody: content: application/json: schema: x-scalar-ignore: true allOf: - type: object required: - to properties: transactional_message_id: description: The transactional message template you want to use. You can call the template by its numerical ID or by the *Trigger Name* that you assigned to the template in the UI (case insensitive). oneOf: - title: ID (integer) type: integer description: The ID of the transactional message you want to send. example: 44 - title: Trigger Name (string) type: string description: The name of trigger for the transactional message you want to send. You set the trigger name in the **Configure Settings** step in the UI when setting up your message. This is case insensitive. example: pwdreset body: type: string description: The HTML body of your message. If you provide a `transactional_message_id`, this overrides the template's body. It's also the fallback when you send AMP email (`body_amp`) to a client that doesn't support AMP. example: Your temporary password is {{message_data.password_reset_token}} body_amp: x-scalar-ignore: true type: string description: AMP-enabled content for your email. If a recipient's email client doesn't support AMP, they receive your `body` content instead. Make sure you're [set up to send AMP](/journeys/channels/email/layouts/amp-for-email/) first. body_plain: type: string description: The plaintext body of your message. If you provide `transactional_message_id`, this overrides the template's plaintext body. subject: type: string description: The subject line for your message. If you provide `transactional_message_id`, this overrides the template's subject. example: Reset your password! from: type: string description: The address your email is from. It must be a [verified sender](/journeys/channels/email/deliverability/authentication/). Quote any display name, like `\"Person\" `. This overrides the template's sender; omit it to use the template or your workspace default. example: support@example.com language: type: string description: 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](/journeys/channels/localization/getting-started/#supported-languages). - x-scalar-ignore: true type: object properties: identifiers: description: Identifies the person represented by your transactional message by one of, and only one of, `id`, `email`, or `cio_id`. oneOf: - title: id type: object required: - id properties: id: type: string description: 'The identifier for the person represented by the transactional message. **NOTE**: If your workspace identifies people by email, use the `email` identifier instead. ' example: 12345 - title: email type: object required: - email properties: email: type: string description: The identifier for the person represented by the transactional message. Use this option if your workspace identifies people by email rather than by `id`. example: cool.person@example.com - title: cio_id type: object required: - cio_id properties: cio_id: type: string description: A unique, immutable identifier for a person, set by Customer.io when you add a person. example: 3000001 message_data: type: object description: An object containing the key-value pairs referenced using liquid in your message. additionalProperties: x-additionalPropertiesName: Liquid Data description: Insert key-values that you want to reference in your message here. example: password_reset_token: abcde-12345-fghij-d888 account_id: 123dj send_at: type: integer description: 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. disable_message_retention: x-scalar-ignore: true type: boolean default: false description: 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`. send_to_unsubscribed: x-scalar-ignore: true type: boolean default: true description: 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`. queue_draft: x-scalar-ignore: true type: boolean description: If true, your transactional message is held as a draft in Customer.io and not sent directly to your audience. You must go to the Deliveries and Drafts page to send your message. default: false auto_create: type: boolean default: false description: If `true` and your `transactional_message_id` doesn't match a record, Customer.io creates an empty record using that value as the *Trigger Name*. The ID must be a string. If the name already belongs to another channel, the request fails with `400`, and numeric IDs ignore this setting. See [details](/journeys/transactional-email/#auto-create-transactional-message-records). - x-scalar-ignore: true type: object properties: to: type: string description: The recipients you want to send to, separated by commas. You can include up to 15 total recipients across `to`, `cc`, and `bcc`, with optional display names in quotes. example: cool.person@example.com cc: type: string description: Carbon copy message recipients, separated by commas. Unlike BCC recipients, CC recipients are visible to everyone who receives the message. Their opens, clicks, and bounces count toward your message metrics. CC recipients count toward the limit of 15 total recipients across the `to`, `cc`, and `bcc` keys. example: cc@example.com bcc: type: string description: Blind copy message recipients. Supports multiple addresses separated by commas. Your request can contain up to 15 total recipients between the `to`, `cc`, and `bcc` keys. example: bcc@example.com fake_bcc: type: boolean description: 'If true, rather than sending true copies to BCC addresses, Customer.io sends a copy of the message with the subject line containing the recipient address(es). ' reply_to: type: string description: The address that recipients can reply to, if different from the `from` address. example: replyto@example.com preheader: x-scalar-ignore: true type: string description: 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. attachments: x-scalar-ignore: true type: object description: A dictionary of attachments where the filename is the key and the value is the base64-encoded contents. The filename must include the extension (i.e. `name.csv`). The total size of all attachments must be less than 2 MB. properties: : type: string format: base64 headers: x-scalar-ignore: true description: A JSON string containing header objects with `name` and `value`. Names and values must be strings, with no non-ASCII characters or spaces. You can't overwrite reserved headers. type: string format: json example: '[{"name":"X-Mailgun-Tag","value":"my-cool-tag"},{"name":"X-Custom-Header","value":"custom-value"}]' disable_css_preprocessing: type: boolean description: 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. example: false default: false tracked: x-scalar-ignore: true type: boolean description: If true, Customer.io tracks opens and link clicks in your message. default: true example: transactional_message_id: 44 to: cool.person@example.com from: override-templated-address@example.com subject: Order receipt identifiers: email: cool.person@example.com message_data: password_reset_token: abcde-12345-fghij-d888 account_id: 123dj attachments: file1.csv: base64encodedcontent file2.pdf: base64encodedcontent headers: X-Mailgun-Tag: my-cool-tag bcc: bcc@example.com disable_message_retention: false send_to_unsubscribed: true tracked: true queue_draft: false disable_css_preprocessing: true responses: '200': description: Returns a unique ID for the delivery. content: application/json: schema: type: object properties: delivery_id: type: string description: A unique identifier for the message. queued_at: type: integer format: unix timestamp description: A Unix timestamp for when Customer.io accepted and queued your request. For scheduled messages (using `send_at`), this is when we received your request, not when the message sends. send_at: type: integer format: unix timestamp description: For a scheduled message, the Unix timestamp when the message is set to send. Returned only when you provide a future `send_at`. '400': description: The request was malformed or the attachment is not base64-encoded. content: application/json: schema: type: object properties: meta: type: object description: Contains errors. properties: error: type: string description: Describes the error that caused your request to fail. example: '`Attachment must be base64 encoded: "filename.xyz" ' '403': description: Your attachment is not in a recognized format. content: application/json: schema: type: object properties: meta: type: object properties: error: type: string description: Describes the error that caused your request to fail. example: Forbidden file type xyz for attachment filename.xyz. '413': description: This typically means your attachment exceeds the size limit. content: application/json: schema: type: object properties: meta: type: object properties: error: type: string description: Describes the error that caused your request to fail. example: Total attachment size exceeds the limit x-codeSamples: - lang: json label: JSON source: "{\n \"transactional_message_id\": 44,\n \"to\": \"cool.person@example.com\",\n \"from\": \"override-templated-address@example.com\",\n \"subject\": \"Order receipt\",\n \"identifiers\": {\n \"email\": \"cool.person@example.com\"\n },\n \"message_data\": {\n \"password_reset_token\": \"abcde-12345-fghij-d888\",\n \"account_id\": \"123dj\"\n },\n \"attachments\": {\n \"file1.csv\": \"base64encodedcontent\",\n \"file2.pdf\": \"base64encodedcontent\"\n },\n \"headers\": {\n \"X-Mailgun-Tag\": \"my-cool-tag\"\n },\n \"bcc\": \"bcc@example.com\",\n \"disable_message_retention\": false,\n \"send_to_unsubscribed\": true,\n \"tracked\": true,\n \"queue_draft\": false,\n \"disable_css_preprocessing\": true\n}" - lang: Shell + Curl source: "curl --request POST \\\n --header 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n --url https://api.customer.io/v1/send/email \\\n --header 'content-type: application/json' \\\n --data '{\"transactional_message_id\":44,\"to\":\"cool.person@example.com\",\"from\":\"override-templated-address@example.com\",\"subject\":\"Order receipt\",\"identifiers\":{\"email\":\"cool.person@example.com\"},\"message_data\":{\"password_reset_token\":\"abcde-12345-fghij-d888\",\"account_id\":\"123dj\"},\"attachments\":{\"file1.csv\":\"base64encodedcontent\",\"file2.pdf\":\"base64encodedcontent\"},\"headers\":{\"X-Mailgun-Tag\":\"my-cool-tag\"},\"bcc\":\"bcc@example.com\",\"disable_message_retention\":false,\"send_to_unsubscribed\":true,\"tracked\":true,\"queue_draft\":false,\"disable_css_preprocessing\":true}'" - lang: Node + Native source: "const http = require(\"https\");\n\nconst options = {\n \"method\": \"POST\",\n \"hostname\": \"api.customer.io\",\n \"port\": null,\n \"path\": \"/v1/send/email\",\n \"headers\": {\n \"content-type\": \"application/json\"\n }\n};\n\nconst req = http.request(options, function (res) {\n const chunks = [];\n\n res.on(\"data\", function (chunk) {\n chunks.push(chunk);\n });\n\n res.on(\"end\", function () {\n const body = Buffer.concat(chunks);\n console.log(body.toString());\n });\n});\n\nreq.write(JSON.stringify({\n transactional_message_id: 44,\n to: 'cool.person@example.com',\n from: 'override-templated-address@example.com',\n subject: 'Order receipt',\n identifiers: {email: 'cool.person@example.com'},\n message_data: {password_reset_token: 'abcde-12345-fghij-d888', account_id: '123dj'},\n attachments: {'file1.csv': 'base64encodedcontent', 'file2.pdf': 'base64encodedcontent'},\n headers: {'X-Mailgun-Tag': 'my-cool-tag'},\n bcc: 'bcc@example.com',\n disable_message_retention: false,\n send_to_unsubscribed: true,\n tracked: true,\n queue_draft: false,\n disable_css_preprocessing: true\n}));\nreq.end();" - lang: Ruby + Native source: 'require ''uri'' require ''net/http'' require ''openssl'' url = URI("https://api.customer.io/v1/send/email") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Post.new(url) request["content-type"] = ''application/json'' request.body = "{\"transactional_message_id\":44,\"to\":\"cool.person@example.com\",\"from\":\"override-templated-address@example.com\",\"subject\":\"Order receipt\",\"identifiers\":{\"email\":\"cool.person@example.com\"},\"message_data\":{\"password_reset_token\":\"abcde-12345-fghij-d888\",\"account_id\":\"123dj\"},\"attachments\":{\"file1.csv\":\"base64encodedcontent\",\"file2.pdf\":\"base64encodedcontent\"},\"headers\":{\"X-Mailgun-Tag\":\"my-cool-tag\"},\"bcc\":\"bcc@example.com\",\"disable_message_retention\":false,\"send_to_unsubscribed\":true,\"tracked\":true,\"queue_draft\":false,\"disable_css_preprocessing\":true}" response = http.request(request) puts response.read_body' - lang: Python + Python3 source: 'import http.client conn = http.client.HTTPSConnection("api.customer.io") payload = "{\"transactional_message_id\":44,\"to\":\"cool.person@example.com\",\"from\":\"override-templated-address@example.com\",\"subject\":\"Order receipt\",\"identifiers\":{\"email\":\"cool.person@example.com\"},\"message_data\":{\"password_reset_token\":\"abcde-12345-fghij-d888\",\"account_id\":\"123dj\"},\"attachments\":{\"file1.csv\":\"base64encodedcontent\",\"file2.pdf\":\"base64encodedcontent\"},\"headers\":{\"X-Mailgun-Tag\":\"my-cool-tag\"},\"bcc\":\"bcc@example.com\",\"disable_message_retention\":false,\"send_to_unsubscribed\":true,\"tracked\":true,\"queue_draft\":false,\"disable_css_preprocessing\":true}" headers = { ''content-type'': "application/json" } conn.request("POST", "/v1/send/email", payload, headers) res = conn.getresponse() data = res.read() print(data.decode("utf-8"))' - lang: Go + Native source: "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\n\turl := \"https://api.customer.io/v1/send/email\"\n\n\tpayload := strings.NewReader(\"{\\\"transactional_message_id\\\":44,\\\"to\\\":\\\"cool.person@example.com\\\",\\\"from\\\":\\\"override-templated-address@example.com\\\",\\\"subject\\\":\\\"Order receipt\\\",\\\"identifiers\\\":{\\\"email\\\":\\\"cool.person@example.com\\\"},\\\"message_data\\\":{\\\"password_reset_token\\\":\\\"abcde-12345-fghij-d888\\\",\\\"account_id\\\":\\\"123dj\\\"},\\\"attachments\\\":{\\\"file1.csv\\\":\\\"base64encodedcontent\\\",\\\"file2.pdf\\\":\\\"base64encodedcontent\\\"},\\\"headers\\\":{\\\"X-Mailgun-Tag\\\":\\\"my-cool-tag\\\"},\\\"bcc\\\":\\\"bcc@example.com\\\",\\\"disable_message_retention\\\":false,\\\"send_to_unsubscribed\\\":true,\\\"tracked\\\":true,\\\"queue_draft\\\":false,\\\"disable_css_preprocessing\\\":true}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"content-type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" /v1/send/in_app: servers: - url: https://api.customer.io description: This API uses bearer authorization, requiring a [token that you generate in the UI](https://fly.customer.io/settings/api_credentials?keyType=app). post: summary: Send a transactional in-app message operationId: sendInApp security: - Bearer-Auth: [] - ServiceAccount-Auth: [] description: 'Send a transactional in-app message. In-app messages render in your application through the Customer.io SDK to the devices associated with the person you target by `identifiers`. You send a message using a `transactional_message_id` for an in-app message template that you''ve set up in the user interface. The `transactional_message_id` can be either the numerical ID for the template or the *Trigger Name* that you assigned the template. You can find your `transactional_message_id` from the code sample in the **Overview** tab for your transactional message in the user interface, or you can look up a list of your transactional messages through the [App API](#tag/Transactional). **Note**: Your workspace must have in-app messaging enabled. Requests sent to a workspace without the in-app capability return `403`. ' tags: - Send Messages parameters: - x-scalar-ignore: true name: X-Workspace-Id in: header required: false description: 'The numeric ID of the workspace you want to send a message in. This header is only needed when you authenticate with a service-account bearer token (`sa_live_…`). Service accounts work across workspaces, so you must supply this header so we know which workspace to send from. You can omit this header when you authenticate with a standard App API key, which is always scoped to one workspace. ' schema: type: integer example: 100 requestBody: content: application/json: schema: x-scalar-ignore: true allOf: - type: object required: - transactional_message_id - identifiers properties: transactional_message_id: description: 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 to the template in the UI (case insensitive). oneOf: - title: ID (integer) type: integer description: The ID of the transactional message you want to send. example: 44 - title: Trigger Name (string) type: string description: The name of trigger for the transactional message you want to send; you set the trigger name in the *Configure Settings* step when setting up your message. This is case insensitive. example: order_confirmation identifiers: description: Identifies the person represented by your transactional message by one of, and only one of, `id`, `email`, or `cio_id`. oneOf: - title: id type: object required: - id properties: id: type: string description: 'The identifier for the person represented by the transactional message. **NOTE**: If your workspace identifies people by email, use the `email` identifier instead. ' example: user_123 - title: email type: object required: - email properties: email: type: string description: The identifier for the person represented by the transactional message. Use this option if your workspace identifies people by email rather than by `id`. example: user@example.com - title: cio_id type: object required: - cio_id properties: cio_id: type: string description: A unique, immutable identifier for a person, set by Customer.io when you add a person. example: 3000001 message_data: type: object description: An object containing the key-value pairs referenced using liquid in the format `{{trigger.}}` in your in-app message. These values populate the `properties` field in the message that the SDK delivers to your application. additionalProperties: x-additionalPropertiesName: Liquid Data description: Insert key-values that you want to reference in your message here. example: order_id: ORD-5678 tracking_url: https://track.example.com/5678 send_at: type: integer description: 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. queue_draft: x-scalar-ignore: true type: boolean description: If true, your transactional message is held as a draft in Customer.io and not sent directly to your audience. You must go to the Deliveries and Drafts page to send your message. default: false language: type: string description: 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](/journeys/channels/localization/getting-started/#supported-languages). auto_create: type: boolean default: false description: Accepted for in-app sends, but of limited use. An auto-created record has no content or layout until you populate it in the UI, so we recommend [creating the in-app message in the UI](/journeys/send/transactional/in-app/) instead. Your `transactional_message_id` must be a new string. example: transactional_message_id: order_confirmation identifiers: id: user_123 message_data: order_id: ORD-5678 tracking_url: https://track.example.com/5678 responses: '200': description: Returns a unique ID for the delivery. content: application/json: schema: type: object properties: delivery_id: type: string description: A unique identifier for the message. queued_at: type: integer format: unix timestamp description: A Unix timestamp for when Customer.io accepted and queued your request. For scheduled messages (using `send_at`), this is when we received your request, not when the message sends. send_at: type: integer format: unix timestamp description: For a scheduled message, the Unix timestamp when the message is set to send. Returned only when you provide a future `send_at`. '400': description: The request was malformed. content: application/json: schema: type: object properties: meta: type: object description: Contains errors. properties: error: type: string description: Describes the error that caused your request to fail. '403': description: Your workspace is not authorized for transactional messaging or in-app messages. content: application/json: schema: type: object properties: meta: type: object properties: error: type: string description: Describes the error that caused your request to fail. example: Account is not authorized for transactional messaging. Contact win@customer.io for support. x-codeSamples: - lang: json label: JSON source: "{\n \"transactional_message_id\": \"order_confirmation\",\n \"identifiers\": {\n \"id\": \"user_123\"\n },\n \"message_data\": {\n \"order_id\": \"ORD-5678\",\n \"tracking_url\": \"https://track.example.com/5678\"\n }\n}" - lang: Shell + Curl source: "curl --request POST \\\n --header 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n --url https://api.customer.io/v1/send/in_app \\\n --header 'content-type: application/json' \\\n --data '{\"transactional_message_id\":\"order_confirmation\",\"identifiers\":{\"id\":\"user_123\"},\"message_data\":{\"order_id\":\"ORD-5678\",\"tracking_url\":\"https://track.example.com/5678\"}}'" - lang: Node + Native source: "const http = require(\"https\");\n\nconst options = {\n \"method\": \"POST\",\n \"hostname\": \"api.customer.io\",\n \"port\": null,\n \"path\": \"/v1/send/in_app\",\n \"headers\": {\n \"content-type\": \"application/json\"\n }\n};\n\nconst req = http.request(options, function (res) {\n const chunks = [];\n\n res.on(\"data\", function (chunk) {\n chunks.push(chunk);\n });\n\n res.on(\"end\", function () {\n const body = Buffer.concat(chunks);\n console.log(body.toString());\n });\n});\n\nreq.write(JSON.stringify({\n transactional_message_id: 'order_confirmation',\n identifiers: {id: 'user_123'},\n message_data: {order_id: 'ORD-5678', tracking_url: 'https://track.example.com/5678'}\n}));\nreq.end();" - lang: Ruby + Native source: 'require ''uri'' require ''net/http'' require ''openssl'' url = URI("https://api.customer.io/v1/send/in_app") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Post.new(url) request["content-type"] = ''application/json'' request.body = "{\"transactional_message_id\":\"order_confirmation\",\"identifiers\":{\"id\":\"user_123\"},\"message_data\":{\"order_id\":\"ORD-5678\",\"tracking_url\":\"https://track.example.com/5678\"}}" response = http.request(request) puts response.read_body' - lang: Python + Python3 source: 'import http.client conn = http.client.HTTPSConnection("api.customer.io") payload = "{\"transactional_message_id\":\"order_confirmation\",\"identifiers\":{\"id\":\"user_123\"},\"message_data\":{\"order_id\":\"ORD-5678\",\"tracking_url\":\"https://track.example.com/5678\"}}" headers = { ''content-type'': "application/json" } conn.request("POST", "/v1/send/in_app", payload, headers) res = conn.getresponse() data = res.read() print(data.decode("utf-8"))' - lang: Go + Native source: "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\n\turl := \"https://api.customer.io/v1/send/in_app\"\n\n\tpayload := strings.NewReader(\"{\\\"transactional_message_id\\\":\\\"order_confirmation\\\",\\\"identifiers\\\":{\\\"id\\\":\\\"user_123\\\"},\\\"message_data\\\":{\\\"order_id\\\":\\\"ORD-5678\\\",\\\"tracking_url\\\":\\\"https://track.example.com/5678\\\"}}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"content-type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" /v1/send/inbox_message: servers: - url: https://api.customer.io description: This API uses bearer authorization, requiring a [token that you generate in the UI](https://fly.customer.io/settings/api_credentials?keyType=app). post: summary: Send a transactional inbox message operationId: sendInboxMessage security: - Bearer-Auth: [] - ServiceAccount-Auth: [] description: 'Send a transactional inbox message. Inbox messages deliver raw JSON payloads to your application through our JavaScript SDK, allowing you to build custom notification centers, message feeds, and other UI components. You send a message using a `transactional_message_id` for an inbox message template created in the user interface. The `transactional_message_id` can be either the numerical ID for the template or the *Trigger Name* that you assigned the template. You can find your `transactional_message_id` from the code sample in the **Overview** tab for your transactional message in the user interface, or you can look up a list of your transactional messages through the [App API](#tag/Transactional). **Note**: Inbox messages are currently available for web platforms only and require the Customer.io In-App Plugin to be installed. ' tags: - Send Messages parameters: - x-scalar-ignore: true name: X-Workspace-Id in: header required: false description: 'The numeric ID of the workspace you want to send a message in. This header is only needed when you authenticate with a service-account bearer token (`sa_live_…`). Service accounts work across workspaces, so you must supply this header so we know which workspace to send from. You can omit this header when you authenticate with a standard App API key, which is always scoped to one workspace. ' schema: type: integer example: 100 requestBody: content: application/json: schema: x-scalar-ignore: true allOf: - type: object required: - transactional_message_id - identifiers properties: transactional_message_id: description: 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 to the template in the UI (case insensitive). oneOf: - title: ID (integer) type: integer description: The ID of the transactional message you want to send. example: 44 - title: Trigger Name (string) type: string description: The name of trigger for the transactional message you want to send; you set the trigger name in the *Configure Settings* step when setting up your message. This is case insensitive. example: order_shipped identifiers: description: Identifies the person represented by your transactional message by one of, and only one of, `id`, `email`, or `cio_id`. oneOf: - title: id type: object required: - id properties: id: type: string description: 'The identifier for the person represented by the transactional message. **NOTE**: If your workspace identifies people by email, use the `email` identifier instead. ' example: user_123 - title: email type: object required: - email properties: email: type: string description: The identifier for the person represented by the transactional message. Use this option if your workspace identifies people by email rather than by `id`. example: user@example.com - title: cio_id type: object required: - cio_id properties: cio_id: type: string description: A unique, immutable identifier for a person, set by Customer.io when you add a person. example: 3000001 message_data: type: object description: An object containing the key-value pairs referenced using liquid in the format `{{trigger.}}` in your inbox message. These values will populate the `properties` field in the message received by your application. additionalProperties: x-additionalPropertiesName: Liquid Data description: Insert key-values that you want to reference in your message here. example: order_id: ORD-5678 tracking_url: https://track.example.com/5678 to: type: string description: Optional override for the recipient. This is typically not needed as the message is sent to the person identified by `identifiers`. send_at: type: integer description: 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. queue_draft: x-scalar-ignore: true type: boolean description: If true, your transactional message is held as a draft in Customer.io and not sent directly to your audience. You must go to the Deliveries and Drafts page to send your message. default: false language: type: string description: 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](/journeys/channels/localization/getting-started/#supported-languages). auto_create: type: boolean default: false description: Accepted for inbox sends, but of limited use. An auto-created record has no content or layout until you populate it in the UI, so we recommend [creating the inbox message in the UI](/journeys/channels/in-app/inbox/send-inbox-txnl/) instead. Your `transactional_message_id` must be a new string. example: 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 product_image: https://cdn.example.com/widget.jpg responses: '200': description: Returns a unique ID for the delivery. content: application/json: schema: type: object properties: delivery_id: type: string description: A unique identifier for the message. queued_at: type: integer format: unix timestamp description: A Unix timestamp for when Customer.io accepted and queued your request. For scheduled messages (using `send_at`), this is when we received your request, not when the message sends. send_at: type: integer format: unix timestamp description: For a scheduled message, the Unix timestamp when the message is set to send. Returned only when you provide a future `send_at`. '400': description: The request was malformed. content: application/json: schema: type: object properties: meta: type: object description: Contains errors. properties: error: type: string description: Describes the error that caused your request to fail. '403': description: Your workspace is not authorized for transactional messaging or inbox messages. content: application/json: schema: type: object properties: meta: type: object properties: error: type: string description: Describes the error that caused your request to fail. example: Account is not authorized for transactional messaging. Contact win@customer.io for support. x-codeSamples: - lang: json label: JSON source: "{\n \"transactional_message_id\": \"order_shipped\",\n \"identifiers\": {\n \"id\": \"user_123\"\n },\n \"message_data\": {\n \"order_id\": \"ORD-5678\",\n \"tracking_url\": \"https://track.example.com/5678\",\n \"product_name\": \"Blue Widget\",\n \"product_image\": \"https://cdn.example.com/widget.jpg\"\n }\n}" - lang: Shell + Curl source: "curl --request POST \\\n --header 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n --url https://api.customer.io/v1/send/inbox_message \\\n --header 'content-type: application/json' \\\n --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\",\"product_image\":\"https://cdn.example.com/widget.jpg\"}}'" - lang: Node + Native source: "const http = require(\"https\");\n\nconst options = {\n \"method\": \"POST\",\n \"hostname\": \"api.customer.io\",\n \"port\": null,\n \"path\": \"/v1/send/inbox_message\",\n \"headers\": {\n \"content-type\": \"application/json\"\n }\n};\n\nconst req = http.request(options, function (res) {\n const chunks = [];\n\n res.on(\"data\", function (chunk) {\n chunks.push(chunk);\n });\n\n res.on(\"end\", function () {\n const body = Buffer.concat(chunks);\n console.log(body.toString());\n });\n});\n\nreq.write(JSON.stringify({\n transactional_message_id: 'order_shipped',\n identifiers: {id: 'user_123'},\n message_data: {\n order_id: 'ORD-5678',\n tracking_url: 'https://track.example.com/5678',\n product_name: 'Blue Widget',\n product_image: 'https://cdn.example.com/widget.jpg'\n }\n}));\nreq.end();" - lang: Ruby + Native source: 'require ''uri'' require ''net/http'' require ''openssl'' url = URI("https://api.customer.io/v1/send/inbox_message") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Post.new(url) 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\",\"product_image\":\"https://cdn.example.com/widget.jpg\"}}" response = http.request(request) puts response.read_body' - lang: Python + Python3 source: 'import http.client conn = http.client.HTTPSConnection("api.customer.io") payload = "{\"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\",\"product_image\":\"https://cdn.example.com/widget.jpg\"}}" headers = { ''content-type'': "application/json" } conn.request("POST", "/v1/send/inbox_message", payload, headers) res = conn.getresponse() data = res.read() print(data.decode("utf-8"))' - lang: Go + Native source: "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\n\turl := \"https://api.customer.io/v1/send/inbox_message\"\n\n\tpayload := strings.NewReader(\"{\\\"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\\\",\\\"product_image\\\":\\\"https://cdn.example.com/widget.jpg\\\"}}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"content-type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" /v1/send/push: servers: - url: https://api.customer.io description: This API uses bearer authorization, requiring a [token that you generate in the UI](https://fly.customer.io/settings/api_credentials?keyType=app). post: summary: Send a transactional push operationId: sendPush security: - Bearer-Auth: [] - ServiceAccount-Auth: [] description: 'Send a transactional push. You send a message using a `transactional_message_id` for a transactional push message template composed in the user interface. You can optionally override any of the template values at send time. The `transactional_message_id` can be either the numerical ID for the template or the *Trigger Name* that you assigned the template. You can find your `transactional_message_id` from the code sample in the **Overview** tab for your transactional message in the user interface, or you can look up a list of your transactional messages through the [App API](#tag/Transactional). ' tags: - Send Messages parameters: - x-scalar-ignore: true name: X-Workspace-Id in: header required: false description: 'The numeric ID of the workspace you want to send a message in. This header is only needed when you authenticate with a service-account bearer token (`sa_live_…`). Service accounts work across workspaces, so you must supply this header so we know which workspace to send from. You can omit this header when you authenticate with a standard App API key, which is always scoped to one workspace. ' schema: type: integer example: 100 requestBody: content: application/json: schema: x-scalar-ignore: true allOf: - type: object required: - transactional_message_id - identifiers properties: transactional_message_id: description: 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 to the template in the UI (case insensitive). oneOf: - title: ID (integer) type: integer description: The ID of the transactional message you want to send. example: 44 - title: Trigger Name (string) type: string description: The name of trigger for the transactional message you want to send; you set the trigger name in the *Configure Settings* step when setting up your message. This is case insensitive. example: pwdreset - x-scalar-ignore: true type: object properties: to: type: string description: The devices you want to send this push to—`all`, `last_used`, or a custom device token from the identified profile. Defaults to `all` and overrides the `To` value from your transactional template. enum: - all - last_used - $device_token default: all title: type: string description: The title for your notification. This overrides the title of the transactional template (referenced by `transactional_message_id`). message: type: string description: The message body for your notification. This overrides the notification body of the transactional template (referenced by `transactional_message_id`). image_url: type: string description: An image URL to show in the push. This overrides Image from the transactional template (referenced by `transactional_message_id`). link: type: string description: A deep link to open when the push is tapped. This overrides Link from the transactional template (referenced by `transactional_message_id`). sound: type: string description: '**For iOS Only**: your notification can alert users with the device''s default notification sound or play no sound at all. ' enum: - default - none default: default custom_data: type: object description: Optional key/value pairs you want to attach to the push payload. Firebase only supports string values. This overrides the Custom Data from your transactional template. custom_device: description: A device to perform an upsert operation at the time of send. The device will be added/updated on the profile from the Identifiers block. allOf: - type: object required: - token properties: token: description: The device token. type: string - x-scalar-ignore: true type: object description: Device information common to the v1 and v2 APIs. required: - platform properties: last_used: type: integer format: unix timestamp description: The `timestamp` when you last identified this device. If you don't pass a timestamp when you add or update a device, we use the time of the request itself. Our SDKs identify a device when a person launches their app. platform: type: string enum: - ios - android description: The device/messaging platform. attributes: type: object description: Attributes that you can reference to segment your audience—like a person's attributes, but specific to a device. These can be either the attributes defined below or custom key-value attributes. properties: device_os: type: string description: The operating system, including the version, on the device. device_model: type: string description: The model of the device a person uses. app_version: type: string description: The version of your app that a customer uses. You might target app versions to let people know when they need to update, or expose them to new features when they do. cio_sdk_version: type: string description: The version of the Customer.io SDK in the app. _last_status: type: string readOnly: true description: The delivery status of the last message sent to the device—sent, bounced, or suppressed. An empty string indicates that that the device hasn't received a push yet. enum: - '' - bounced - sent - suppressed device_locale: type: string description: The device's [IETF language code](/journeys/channels/localization/getting-started/#supported-languages), such as `en-MX` or `es-ES`. push_enabled: type: string description: If `"true"`, the device is opted-in and can receive push notifications. enum: - 'true' - 'false' additionalProperties: x-additionalPropertiesName: Custom Device Attributes description: Custom properties that you want to associate with the device. type: string custom_payload: type: object description: Optional key/value pairs you want to attach to the push payload. Firebase only supports string values. This overrides all other payload values, including the Custom Payload from your transactional template. properties: ios: x-scalar-ignore: true description: Your payload changes depending on whether you send to iOS devices through Google's Firebase Cloud Messaging (FCM) or Apple's Push Notification service (APNs). oneOf: - x-scalar-ignore: true type: object required: - message properties: message: type: object description: The base object for all FCM payloads. required: - apns properties: apns: type: object required: - payload description: Defines a payload for iOS devices sent through Firebase Cloud Messaging (FCM). properties: headers: description: Headers defined by [Apple's payload reference](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns) that you want to pass through FCM. type: object payload: type: object description: Contains a push payload. properties: CIO: type: object description: Contains properties interpreted by the Customer.io iOS SDK. required: - push properties: push: type: object description: A push payload for the iOS SDK. properties: title: x-scalar-ignore: true type: string description: The title of your push notification. body: x-scalar-ignore: true type: string description: The body of your push notification. link: x-scalar-ignore: true type: string description: A deep link (to a page in your app), or a link to a web page. image: x-scalar-ignore: true type: string description: The URL of an HTTPS image that you want to use for your message. aps: x-scalar-ignore: true type: object description: A push payload intended for an iOS device. properties: alert: oneOf: - title: Simple alert type: string description: A simple alert message. - title: Complex alert type: object properties: body: x-scalar-ignore: true type: string description: The body of your push notification. title: x-scalar-ignore: true type: string description: The title of your push notification. subtitle: description: Additional information that explains the purpose of the notification. type: string launch-image: description: The name of the launch image file you want to display. When a user launches your app, they'll see this image or storyboard file rather than your app’s normal launch image. type: string title-loc-key: description: The key for a localized title string in your app’s Localizable.strings files. type: string title-loc-args: type: array description: An array of replacement value strings for variables in your title string. Each %@ character in the title-loc-key is replaced by a value from this array, in the order they appear in the title string. items: type: string subtitle-loc-key: description: The key for a localized subtitle string in your app’s Localizable.strings file. type: string subtitle-loc-args: type: array description: An array of replacement value strings for variables in your subtitle string. Each %@ character in the subtitle-loc-key is replaced by a value from this array, in the order they appear in the subtitle string. items: type: string loc-key: description: The key for a localized message string in your app’s Localizable.strings file. type: string loc-args: type: array description: An array of replacement value strings for variables in your message text. Each %@ character in the loc-key is replaced by a value from this array, in the order they appear in the message body. items: type: string badge: type: integer description: The number you want to display on your app's icon. Set to 0 to remove the current badge, if any. sound: oneOf: - title: Regular alert type: string description: The name of a sound file in your app’s main bundle or in the Library/Sounds folder of your app’s container directory. Use “default” to play the system sound. For critical alerts, you'll pass an object instead. - title: Critical alert type: object properties: critical: type: integer description: 1 indicates critical. 0 is not critical. name: type: string description: The name of a sound file in your app’s main bundle or in the Library/Sounds folder of your app’s container directory. Use “default” to play the system sound. volume: type: number description: The volume for a critical alert between 0 and 1, where 0 is silent and 1 is full volume. thread-id: type: string description: An identifier to group related notifications. category: type: string description: The notification’s type. This string must correspond to the identifier of one of the `UNNotificationCategory` objects you register at launch time. content-available: type: integer description: The background notification flag. Use `1` without an `alert` to perform a silent update. `0` indicates a normal push notification. mutable-content: type: integer description: Set this to `1` if you use the Customer.io SDK, so you can support images and delivered metrics in your push notifications. It passes the notification to your service extension before delivery. target-content-id: type: string description: The identifier of the window brought forward. interruption-level: type: string description: Indicates the importance and delivery timing of a notification. enum: - passive - active - time-sensitive - critical relevance-score: type: number description: A number between 0 and 1. The highest score is considered the "most relevant" and is featured in the notification summary. additionalProperties: description: Additional properties that you've set up your app to interpret outside of the Customer.io SDK. x-additionalPropertiesName: Custom key-value pairs - x-scalar-ignore: true type: object properties: CIO: type: object required: - push description: Contains options supported by the Customer.io SDK. properties: push: type: object description: Describes push notification options supported by the CIO SDK. properties: link: x-scalar-ignore: true type: string description: A deep link (to a page in your app), or a link to a web page. image: x-scalar-ignore: true type: string description: The URL of an HTTPS image that you want to use for your message. aps: x-scalar-ignore: true type: object description: A push payload intended for an iOS device. properties: alert: oneOf: - title: Simple alert type: string description: A simple alert message. - title: Complex alert type: object properties: body: x-scalar-ignore: true type: string description: The body of your push notification. title: x-scalar-ignore: true type: string description: The title of your push notification. subtitle: description: Additional information that explains the purpose of the notification. type: string launch-image: description: The name of the launch image file you want to display. When a user launches your app, they'll see this image or storyboard file rather than your app’s normal launch image. type: string title-loc-key: description: The key for a localized title string in your app’s Localizable.strings files. type: string title-loc-args: type: array description: An array of replacement value strings for variables in your title string. Each %@ character in the title-loc-key is replaced by a value from this array, in the order they appear in the title string. items: type: string subtitle-loc-key: description: The key for a localized subtitle string in your app’s Localizable.strings file. type: string subtitle-loc-args: type: array description: An array of replacement value strings for variables in your subtitle string. Each %@ character in the subtitle-loc-key is replaced by a value from this array, in the order they appear in the subtitle string. items: type: string loc-key: description: The key for a localized message string in your app’s Localizable.strings file. type: string loc-args: type: array description: An array of replacement value strings for variables in your message text. Each %@ character in the loc-key is replaced by a value from this array, in the order they appear in the message body. items: type: string badge: type: integer description: The number you want to display on your app's icon. Set to 0 to remove the current badge, if any. sound: oneOf: - title: Regular alert type: string description: The name of a sound file in your app’s main bundle or in the Library/Sounds folder of your app’s container directory. Use “default” to play the system sound. For critical alerts, you'll pass an object instead. - title: Critical alert type: object properties: critical: type: integer description: 1 indicates critical. 0 is not critical. name: type: string description: The name of a sound file in your app’s main bundle or in the Library/Sounds folder of your app’s container directory. Use “default” to play the system sound. volume: type: number description: The volume for a critical alert between 0 and 1, where 0 is silent and 1 is full volume. thread-id: type: string description: An identifier to group related notifications. category: type: string description: The notification’s type. This string must correspond to the identifier of one of the `UNNotificationCategory` objects you register at launch time. content-available: type: integer description: The background notification flag. Use `1` without an `alert` to perform a silent update. `0` indicates a normal push notification. mutable-content: type: integer description: Set this to `1` if you use the Customer.io SDK, so you can support images and delivered metrics in your push notifications. It passes the notification to your service extension before delivery. target-content-id: type: string description: The identifier of the window brought forward. interruption-level: type: string description: Indicates the importance and delivery timing of a notification. enum: - passive - active - time-sensitive - critical relevance-score: type: number description: A number between 0 and 1. The highest score is considered the "most relevant" and is featured in the notification summary. android: x-scalar-ignore: true type: object description: A custom push payload for Android devices. required: - message properties: message: type: object description: The parent object for Android custom push payloads. properties: notification: type: object description: Contains the push body and title. properties: title: x-scalar-ignore: true type: string description: The title of your push notification. body: x-scalar-ignore: true type: string description: The body of your push notification. data: type: object description: Contains key-value pairs that your app interprets. additionalProperties: x-additionalPropertiesName: Attachment Names x-doNotRender: true type: string android: type: object description: Contains custom push options for your notification. properties: notification: x-scalar-ignore: true type: object description: Properties supported specifically by Android on FCM. properties: icon: type: string description: Sets the notification icon to `myicon` for drawable resource `myicon`. If you don't send this key, FCM displays the launcher icon from your app manifest. sound: type: string description: The sound that plays when the device receives the notification. Supports `"default"` or the filename of a sound resource bundled in your app. Sound files must reside in `/res/raw/`. tag: type: string description: An identifier you use to replace an existing notification. If a notification with the same tag is already showing, the new one replaces it. Leave it empty to create a new notification each time. color: type: string description: The notification's icon color in `#rrggbb` format. click_action: type: string description: The action that occurs when a user taps on the notification. Launches an activity with a matching intent filter when a person taps the notification. body_loc_key: type: string description: String resource key used to localize the body text. See Android [String resources](https://developer.android.com/guide/topics/resources/string-resource/). body_loc_arg: type: string description: Variable string values used in place of the format specifiers in `body_loc_key` to localize the body text to the user's current localization. See Formatting and Styling for more information. title_loc_key: type: string description: String resource key used to localize the title text. See Android [String resources](https://developer.android.com/guide/topics/resources/string-resource/). title_loc_arg: type: string description: Variable string values used in place of the format specifiers in `title_loc_key` to localize the title text to the user's current localization. See Formatting and Styling for more information. language: type: string description: 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](/journeys/channels/localization/getting-started/#supported-languages). - x-scalar-ignore: true type: object properties: identifiers: description: Identifies the person represented by your transactional message by one of, and only one of, `id`, `email`, or `cio_id`. oneOf: - title: id type: object required: - id properties: id: type: string description: 'The identifier for the person represented by the transactional message. **NOTE**: If your workspace identifies people by email, use the `email` identifier instead. ' example: 12345 - title: email type: object required: - email properties: email: type: string description: The identifier for the person represented by the transactional message. Use this option if your workspace identifies people by email rather than by `id`. example: cool.person@example.com - title: cio_id type: object required: - cio_id properties: cio_id: type: string description: A unique, immutable identifier for a person, set by Customer.io when you add a person. example: 3000001 message_data: type: object description: An object containing the key-value pairs referenced using liquid in your message. additionalProperties: x-additionalPropertiesName: Liquid Data description: Insert key-values that you want to reference in your message here. example: password_reset_token: abcde-12345-fghij-d888 account_id: 123dj send_at: type: integer description: 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. disable_message_retention: x-scalar-ignore: true type: boolean default: false description: 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`. send_to_unsubscribed: x-scalar-ignore: true type: boolean default: true description: 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`. queue_draft: x-scalar-ignore: true type: boolean description: If true, your transactional message is held as a draft in Customer.io and not sent directly to your audience. You must go to the Deliveries and Drafts page to send your message. default: false auto_create: type: boolean default: false description: If `true` and your `transactional_message_id` doesn't match a record, Customer.io creates an empty record using that value as the *Trigger Name*. The ID must be a string. If the name already belongs to another channel, the request fails with `400`, and numeric IDs ignore this setting. See [details](/journeys/transactional-email/#auto-create-transactional-message-records). example: transactional_message_id: 44 title: Did you really login from a new location? identifiers: id: 12345 message_data: password_reset_token: abcde-12345-fghij-d888 account_id: 123dj responses: '200': description: Returns a unique ID for the delivery. content: application/json: schema: type: object properties: delivery_id: type: string description: A unique identifier for the message. queued_at: type: integer format: unix timestamp description: A Unix timestamp for when Customer.io accepted and queued your request. For scheduled messages (using `send_at`), this is when we received your request, not when the message sends. send_at: type: integer format: unix timestamp description: For a scheduled message, the Unix timestamp when the message is set to send. Returned only when you provide a future `send_at`. '400': description: The request was malformed. content: application/json: schema: type: object properties: meta: type: object description: Contains errors. properties: error: type: string description: Describes the error that caused your request to fail. '403': description: You don't have push enabled for your workspace. content: application/json: schema: type: object properties: meta: type: object properties: error: type: string description: Describes the error that caused your request to fail. example: Push messaging is not enabled for your workspace. x-codeSamples: - lang: json label: JSON source: "{\n \"transactional_message_id\": 44,\n \"title\": \"Did you really login from a new location?\",\n \"identifiers\": {\n \"id\": 12345\n },\n \"message_data\": {\n \"password_reset_token\": \"abcde-12345-fghij-d888\",\n \"account_id\": \"123dj\"\n }\n}" - lang: Shell + Curl source: "curl --request POST \\\n --header 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n --url https://api.customer.io/v1/send/push \\\n --header 'content-type: application/json' \\\n --data '{\"transactional_message_id\":44,\"title\":\"Did you really login from a new location?\",\"identifiers\":{\"id\":12345},\"message_data\":{\"password_reset_token\":\"abcde-12345-fghij-d888\",\"account_id\":\"123dj\"}}'" - lang: Node + Native source: "const http = require(\"https\");\n\nconst options = {\n \"method\": \"POST\",\n \"hostname\": \"api.customer.io\",\n \"port\": null,\n \"path\": \"/v1/send/push\",\n \"headers\": {\n \"content-type\": \"application/json\"\n }\n};\n\nconst req = http.request(options, function (res) {\n const chunks = [];\n\n res.on(\"data\", function (chunk) {\n chunks.push(chunk);\n });\n\n res.on(\"end\", function () {\n const body = Buffer.concat(chunks);\n console.log(body.toString());\n });\n});\n\nreq.write(JSON.stringify({\n transactional_message_id: 44,\n title: 'Did you really login from a new location?',\n identifiers: {id: 12345},\n message_data: {password_reset_token: 'abcde-12345-fghij-d888', account_id: '123dj'}\n}));\nreq.end();" - lang: Ruby + Native source: 'require ''uri'' require ''net/http'' require ''openssl'' url = URI("https://api.customer.io/v1/send/push") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Post.new(url) request["content-type"] = ''application/json'' request.body = "{\"transactional_message_id\":44,\"title\":\"Did you really login from a new location?\",\"identifiers\":{\"id\":12345},\"message_data\":{\"password_reset_token\":\"abcde-12345-fghij-d888\",\"account_id\":\"123dj\"}}" response = http.request(request) puts response.read_body' - lang: Python + Python3 source: 'import http.client conn = http.client.HTTPSConnection("api.customer.io") payload = "{\"transactional_message_id\":44,\"title\":\"Did you really login from a new location?\",\"identifiers\":{\"id\":12345},\"message_data\":{\"password_reset_token\":\"abcde-12345-fghij-d888\",\"account_id\":\"123dj\"}}" headers = { ''content-type'': "application/json" } conn.request("POST", "/v1/send/push", payload, headers) res = conn.getresponse() data = res.read() print(data.decode("utf-8"))' - lang: Go + Native source: "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\n\turl := \"https://api.customer.io/v1/send/push\"\n\n\tpayload := strings.NewReader(\"{\\\"transactional_message_id\\\":44,\\\"title\\\":\\\"Did you really login from a new location?\\\",\\\"identifiers\\\":{\\\"id\\\":12345},\\\"message_data\\\":{\\\"password_reset_token\\\":\\\"abcde-12345-fghij-d888\\\",\\\"account_id\\\":\\\"123dj\\\"}}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"content-type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" /v1/send/sms: servers: - url: https://api.customer.io description: This API uses bearer authorization, requiring a [token that you generate in the UI](https://fly.customer.io/settings/api_credentials?keyType=app). post: summary: Send a transactional SMS operationId: sendSMS security: - Bearer-Auth: [] - ServiceAccount-Auth: [] description: 'Send a transactional SMS message. To send a message, you''ll need to provide a `transactional_message_id`. This is either the numerical ID of your transactional message template or the *Trigger Name* that you assigned the template. You can find your `transactional_message_id` from the code sample in the **Overview** tab for your transactional message in the user interface, or you can look up a list of your transactional messages through the [App API](#tag/Transactional). ' tags: - Send Messages parameters: - x-scalar-ignore: true name: X-Workspace-Id in: header required: false description: 'The numeric ID of the workspace you want to send a message in. This header is only needed when you authenticate with a service-account bearer token (`sa_live_…`). Service accounts work across workspaces, so you must supply this header so we know which workspace to send from. You can omit this header when you authenticate with a standard App API key, which is always scoped to one workspace. ' schema: type: integer example: 100 requestBody: content: application/json: schema: x-scalar-ignore: true allOf: - type: object required: - transactional_message_id - identifiers properties: transactional_message_id: description: 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 to the template in the UI (case insensitive). oneOf: - title: ID (integer) type: integer description: The ID of the transactional message you want to send. example: 44 - title: Trigger Name (string) type: string description: The name of trigger for the transactional message you want to send; you set the trigger name in the *Configure Settings* step when setting up your message. This is case insensitive. example: verification_code - type: object required: - to properties: to: type: string description: The phone number you want to send your SMS to. Use E.164 format, like `+15551234567`, or Liquid if you store phone numbers as attributes. example: '{{customer.phone}}' from: type: string description: The phone number or sender ID your SMS is from. It must be verified in your Twilio account. This overrides the template's sender. Use E.164 format for a phone number. example: '+15551234567' tracked: type: boolean default: true description: Whether to track link clicks for this SMS. Defaults to the transactional message's own tracking setting. language: type: string description: 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](/journeys/channels/localization/getting-started/#supported-languages). - x-scalar-ignore: true type: object properties: identifiers: description: Identifies the person represented by your transactional message by one of, and only one of, `id`, `email`, or `cio_id`. oneOf: - title: id type: object required: - id properties: id: type: string description: 'The identifier for the person represented by the transactional message. **NOTE**: If your workspace identifies people by email, use the `email` identifier instead. ' example: 12345 - title: email type: object required: - email properties: email: type: string description: The identifier for the person represented by the transactional message. Use this option if your workspace identifies people by email rather than by `id`. example: cool.person@example.com - title: cio_id type: object required: - cio_id properties: cio_id: type: string description: A unique, immutable identifier for a person, set by Customer.io when you add a person. example: 3000001 message_data: type: object description: An object containing the key-value pairs referenced using liquid in your message. additionalProperties: x-additionalPropertiesName: Liquid Data description: Insert key-values that you want to reference in your message here. example: password_reset_token: abcde-12345-fghij-d888 account_id: 123dj send_at: type: integer description: 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. disable_message_retention: x-scalar-ignore: true type: boolean default: false description: 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`. send_to_unsubscribed: x-scalar-ignore: true type: boolean default: true description: 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`. queue_draft: x-scalar-ignore: true type: boolean description: If true, your transactional message is held as a draft in Customer.io and not sent directly to your audience. You must go to the Deliveries and Drafts page to send your message. default: false auto_create: type: boolean default: false description: If `true` and your `transactional_message_id` doesn't match a record, Customer.io creates an empty record using that value as the *Trigger Name*. The ID must be a string. If the name already belongs to another channel, the request fails with `400`, and numeric IDs ignore this setting. See [details](/journeys/transactional-email/#auto-create-transactional-message-records). example: transactional_message_id: confirmation code to: '+15559876543' from: '+15551234567' identifiers: id: '123456' message_data: confirmation_code: '123456' account_name: Jane Doe responses: '200': description: Returns a unique ID for the delivery. content: application/json: schema: type: object properties: delivery_id: type: string description: A unique identifier for the message. queued_at: type: integer format: unix timestamp description: A Unix timestamp for when Customer.io accepted and queued your request. For scheduled messages (using `send_at`), this is when we received your request, not when the message sends. send_at: type: integer format: unix timestamp description: For a scheduled message, the Unix timestamp when the message is set to send. Returned only when you provide a future `send_at`. '400': description: The request was malformed. content: application/json: schema: type: object properties: meta: type: object description: Contains errors. properties: error: type: string description: Describes the error that caused your request to fail. example: '`Invalid phone number format. Phone numbers must be in E.164 format.` ' '403': description: You don't have SMS enabled. content: application/json: schema: type: object properties: meta: type: object properties: error: type: string description: Describes the error that caused your request to fail. example: SMS messaging is not enabled for your workspace. x-codeSamples: - lang: json label: JSON source: "{\n \"transactional_message_id\": \"confirmation code\",\n \"to\": \"+15559876543\",\n \"from\": \"+15551234567\",\n \"identifiers\": {\n \"id\": \"123456\"\n },\n \"message_data\": {\n \"confirmation_code\": \"123456\",\n \"account_name\": \"Jane Doe\"\n }\n}" - lang: Shell + Curl source: "curl --request POST \\\n --header 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n --url https://api.customer.io/v1/send/sms \\\n --header 'content-type: application/json' \\\n --data '{\"transactional_message_id\":\"confirmation code\",\"to\":\"+15559876543\",\"from\":\"+15551234567\",\"identifiers\":{\"id\":\"123456\"},\"message_data\":{\"confirmation_code\":\"123456\",\"account_name\":\"Jane Doe\"}}'" - lang: Node + Native source: "const http = require(\"https\");\n\nconst options = {\n \"method\": \"POST\",\n \"hostname\": \"api.customer.io\",\n \"port\": null,\n \"path\": \"/v1/send/sms\",\n \"headers\": {\n \"content-type\": \"application/json\"\n }\n};\n\nconst req = http.request(options, function (res) {\n const chunks = [];\n\n res.on(\"data\", function (chunk) {\n chunks.push(chunk);\n });\n\n res.on(\"end\", function () {\n const body = Buffer.concat(chunks);\n console.log(body.toString());\n });\n});\n\nreq.write(JSON.stringify({\n transactional_message_id: 'confirmation code',\n to: '+15559876543',\n from: '+15551234567',\n identifiers: {id: '123456'},\n message_data: {confirmation_code: '123456', account_name: 'Jane Doe'}\n}));\nreq.end();" - lang: Ruby + Native source: 'require ''uri'' require ''net/http'' require ''openssl'' url = URI("https://api.customer.io/v1/send/sms") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Post.new(url) request["content-type"] = ''application/json'' request.body = "{\"transactional_message_id\":\"confirmation code\",\"to\":\"+15559876543\",\"from\":\"+15551234567\",\"identifiers\":{\"id\":\"123456\"},\"message_data\":{\"confirmation_code\":\"123456\",\"account_name\":\"Jane Doe\"}}" response = http.request(request) puts response.read_body' - lang: Python + Python3 source: 'import http.client conn = http.client.HTTPSConnection("api.customer.io") payload = "{\"transactional_message_id\":\"confirmation code\",\"to\":\"+15559876543\",\"from\":\"+15551234567\",\"identifiers\":{\"id\":\"123456\"},\"message_data\":{\"confirmation_code\":\"123456\",\"account_name\":\"Jane Doe\"}}" headers = { ''content-type'': "application/json" } conn.request("POST", "/v1/send/sms", payload, headers) res = conn.getresponse() data = res.read() print(data.decode("utf-8"))' - lang: Go + Native source: "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\n\turl := \"https://api.customer.io/v1/send/sms\"\n\n\tpayload := strings.NewReader(\"{\\\"transactional_message_id\\\":\\\"confirmation code\\\",\\\"to\\\":\\\"+15559876543\\\",\\\"from\\\":\\\"+15551234567\\\",\\\"identifiers\\\":{\\\"id\\\":\\\"123456\\\"},\\\"message_data\\\":{\\\"confirmation_code\\\":\\\"123456\\\",\\\"account_name\\\":\\\"Jane Doe\\\"}}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"content-type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}" components: securitySchemes: Bearer-Auth: type: http scheme: bearer description: 'The App API uses a bearer authentication scheme. You can generate a bearer token, known as an **App API Key**, with a defined scope in [your account settings](https://fly.customer.io/settings/api_credentials?keyType=app). [Learn more about bearer authorization in Customer.io](/accounts/settings/managing-credentials). ' ServiceAccount-Auth: x-scalar-ignore: true type: http scheme: bearer bearerFormat: sa_live_ description: 'Transactional send endpoints (`/v1/send/email`, `/v1/send/push`, `/v1/send/sms`, `/v1/send/in_app`, `/v1/send/inbox_message`) also accept a service-account bearer token, prefixed with `sa_live_`. Service-account tokens work across workspaces, so you must pass the target workspace as the `X-Workspace-Id` header on each request. Service-account tokens are intended for testing and one-off sends—for example, using the Customer.io CLI with an AI agent like Claude to verify that a transactional message renders correctly before wiring it into your production backend. **For the production integration that triggers the message from your application, use an App API Key instead**: it''s workspace-scoped, easier to rotate, and has a smaller blast radius. Service-account tokens are server-side credentials. Treat them like any API key—keep them in environment variables or a secret manager, and never embed them in client-side code, mobile apps, or other untrusted contexts. ' bearerAuth: type: http scheme: bearer description: API key passed as a Bearer token