# Operations API endpoints organized by functionality. Each section groups related operations for managing different aspects of the platform. # A/B Tests > Create A/B Tests using the `/api/experiments` endpoint. An experiment or A/B test is a set of distinct push notification variants sent to subsets of an audience. You can create up to 26 notification variants and send each variant to an audience subset. {{< important >}} The A/B Tests API is unrelated to the [current version of A/B testing](/docs/guides/experimentation/a-b-tests/messages/). For more information about this API, including its dashboard equivalent, see [Legacy message A/B tests](/docs/guides/experimentation/a-b-tests/messages-legacy/). {{< /important >}} ## Create experiment (A/B Test) {#createexperiment} Create an experiment. The body of the request should consist of a single experiment object. The experiment is processed and sent immediately unless a schedule is present. [Jump to examples ↓](#createexperiment-examples) ### `POST /api/experiments` {{< important >}} The A/B Tests API is unrelated to the [current version of A/B testing](/docs/guides/experimentation/a-b-tests/messages/). For more information about this API, including its dashboard equivalent, see [Legacy message A/B tests](/docs/guides/experimentation/a-b-tests/messages-legacy/). {{< /important >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) **Request body** **Content-Type:** `application/json` [Experiment object]({{< ref "/developer/rest-api/ua/schemas/others/" >}}#experimentobject) **Responses** **`201`** The experiment was created. Response headers: | Name | Type | Description | |------|------|-------------| | `Location` | `string` | The newly created experiment. | Response body: **Content-Type:** `application/json` - **`experiment_id`** `string` Unique identifier for an experiment. Format: `uuid` Example: `0f7704e9-5dc0-4f7d-9964-e89055701b0a` - **`ok`** `boolean` **REQUIRED** If true, the experiment was successfully created. If false, the experiment was not created. - **`operation_id`** `string` A unique string that represents a single API call, used to identify the operation or side effects in reporting and troubleshooting logs. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`push_id`** `string` Unique identifier for a push. Format: `uuid` Example: `7e13f060-594c-11e4-8ed6-0800200c9a66` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/experiments HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "name": "Experiment 1", "audience": {"tag": "earlyBirds"}, "device_types": [ "ios", "android" ], "variants": [ { "push": { "notification": { "alert": "message 1" } } }, { "push": { "notification": { "alert": "message 2" } } } ] } ``` ```http HTTP/1.1 201 Created Content-Length: 123 Location: https://go.urbanairship.com/api/experiments/0f7704e9-5dc0-4f7d-9964-e89055701b0a Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : "true", "operation_id" : "03ca94a3-2b27-42f6-be7e-41efc2612cd4", "experiment_id" : "0f7704e9-5dc0-4f7d-9964-e89055701b0a", "push_id" : "7e13f060-594c-11e4-8ed6-0800200c9a66" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); Schedule schedule = Schedule.newBuilder() .setScheduledTimestamp(DateTime.now().plusMinutes(5)) .build(); Variant variantOne = Variant.newBuilder() .setPushPayload(VariantPushPayload.newBuilder() .setNotification(Notification.newBuilder() .setAlert("message 1") .build() ) .build()) .setSchedule(schedule) .build(); Variant variantTwo = Variant.newBuilder() .setPushPayload(VariantPushPayload.newBuilder() .setNotification(Notification.newBuilder() .setAlert("message 2") .build() ) .build()) .setSchedule(schedule) .build(); Experiment experiment = Experiment.newBuilder() .setName("Experiment 1") .setDescription("Testing description") .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS, DeviceType.ANDROID)) .setAudience(Selectors.tag("earlyBirds")) .addVariant(variantOne) .addVariant(variantTwo) .build(); ExperimentRequest request = ExperimentRequest.newRequest(experiment); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, ABTest, Experiment, Variant ) from urbanairship.push import notification client = BasicAuthClient( key='', secret='' ) # Create push notifications for variants push_1 = notification(alert='message 1') push_2 = notification(alert='message 2') # Create variants variants = [ Variant(push=push_1), Variant(push=push_2) ] # Create experiment experiment = Experiment( audience={'tag': 'earlyBirds'}, device_types=['ios', 'android'], variants=variants, name='Experiment 1' ) # Create and send experiment ab_test = ABTest(airship=client) response = ab_test.create(experiment=experiment) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') variant_one = UA::Variant.new(client: airship) variant_one.push = { "notification": { "alert": "message 1" } } variant_two = UA::Variant.new(client: airship) variant_two.push = { "notification": { "alert": "message 2" } } experiment = UA::Experiment.new(client: airship) experiment.name = 'Experiment 1' experiment.description = 'Example experiment' experiment.audience = UA.tag('earlyBirds') experiment.device_types = ['ios','android'] experiment.variants << variant_one.payload experiment.variants << variant_two.payload ab_test = UA::AbTest.new(client: airship) ab_test.experiment_object = experiment.payload ab_test.create_ab_test ``` --- ## Delete experiment {#deleteexperiment} Delete a scheduled experiment. You can only delete experiments before they start; attempting to delete an experiment that has already started or completed will return an HTTP 405 response ("Method not allowed"). [Jump to examples ↓](#deleteexperiment-examples) ### `DELETE /api/experiments/scheduled/{experiment_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `experiment_id` | `string` | Required | The unique identifier of the experiment. | **Responses** **`200`** Returned if the experiment has been successfully deleted. Response body: **Content-Type:** `application/json` - **`ok`** `boolean` **REQUIRED** Success. - **`operation_id`** `string` A unique string that represents a single API call, used to identify the operation or side effects in reporting and troubleshooting logs. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`405`** Returned when a request is made using an HTTP method not supported by the endpoint. For example, sending a DELETE to /api/schedules. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http DELETE /api/experiments/scheduled/0f7704e9-5dc0-4f7d-9964-e89055701b0a HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Length: 123 Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : "true", "operation_id" : "03ca94a3-2b27-42f6-be7e-41efc2612cd4" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); ExperimentDeleteRequest request = ExperimentDeleteRequest.newRequest("0f7704e9-5dc0-4f7d-9964-e89055701b0a"); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, ABTest ) client = BasicAuthClient( key='', secret='' ) ab_test = ua.ABTest(client) ab_test.experiment_id = "0f7704e9-5dc0-4f7d-9964-e89055701b0a" response = ab_test.delete() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') ab_test = UA::AbTest.new(client: airship) ab_test.experiment_id = '0f7704e9-5dc0-4f7d-9964-e89055701b0a' ab_test.delete_ab_test ``` --- ## Experiment listing {#getexperiments} List experiments, sorted by `created_at` [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) from newest to oldest. Responses are paginated. Use optional `limit` and `offset` parameters to navigate results. [Jump to examples ↓](#getexperiments-examples) ### `GET /api/experiments` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `limit` | `integer` | | Positive maximum number of elements to return per page. The default `limit` is 10 entries with a maximum of 100 entries. Min: 1 Max: 100 | | `offset` | `integer` | | A zero-based integer offset into the result set. If you do not use an offset, results will begin with the most recently sent experiment. If `offset` is greater than the number of queryable experiments, an empty result will be returned. | **Responses** **`200`** Returned on success, with the JSON representation of the experiments in the body of the response. Response body: **Content-Type:** `application/json` - **`count`** `integer` The number of items returned in this page of results. - **`experiments`** `array` <[Experiment object]({{< ref "/developer/rest-api/ua/schemas/others/" >}}#experimentobject)> Experiment objects sorted by either `created_at` from newest to oldest. The number of objects will never exceed the limit specified in the request. - **`next_page`** `string` A relative URL leading to the next page of results. If there are no more results, next_page is absent. - **`ok`** `boolean` **REQUIRED** If true, the call was successful. - **`total_count`** `integer` The total number of results. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/experiments HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Length: 123 Data-Attribute: experiments Count: 2 Total-Count: 2 Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : "true", "count" : 2, "total_count" : 2, "experiments" : [{ "name" : "Experiment 1", "control" : 0.33, "audience" : "all", "device_types": [ "ios", "android" ], "variants" : [{ "push" : { "notification" : { "alert" : "message 1" } }, "id" : 0, }, { "push" : { "notification" : { "alert" : "message 2" } }, "id" : 1, }], "id" : "b5bc3dd1-9ea4-4208-b5f1-9e7ac3fe0502", "created_at" : "2020-03-03T21:08:05", "push_id" : "07cec298-6b8c-49f9-8e03-0448a06f4aac" }, { "name" : "Experiment 2", "description" : "The second experiment", "audience" : "all", "device_types": [ "ios", "android" ], "variants" : [{ "push" : { "notification" : { "alert" : "message 1" } }, "id" : 0, }, { "push" : { "notification" : { "alert" : "message 2" } }, "id" : 1, }], "id" : "e464aa7e-be40-4994-a290-1bbada7187d8", "created_at" : "2020-03-03T21:08:05", "push_id" : "07cec298-6b8c-49f9-8e03-0448a06f4aac" }] } ``` ```python from urbanairship import ( BasicAuthClient, ABTest ) client = BasicAuthClient( key='', secret='' ) ab_test = ABTest(airship=client) response = ab_test.list_experiments() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') ab_test = UA::AbTest.new(client: airship) ab_test.limit = 5 ab_test.list_ab_test ``` --- ## Experiment lookup {#getexperiment} Look up an experiment (A/B Test). [Jump to examples ↓](#getexperiment-examples) ### `GET /api/experiments/{experiment_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `experiment_id` | `string` | Required | The ID of the experiment you want to look up. | **Responses** **`200`** Returned on success, with the JSON representation of the experiment in the body of the response. Response body: **Content-Type:** `application/json` - **`experiment`** `object` <[Experiment object]({{< ref "/developer/rest-api/ua/schemas/others/" >}}#experimentobject)> An experiment object describes an A/B test, including the audience and variant portions. - **`ok`** `boolean` **REQUIRED** If true, the operation completed successfully and returns a result set. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/experiments/0f7704e9-5dc0-4f7d-9964-e89055701b0a HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Length: 123 Data-Attribute: experiment Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : "true", "experiment" : { "id" : "0f7704e9-5dc0-4f7d-9964-e89055701b0a", "push_id": "d00f07b0-594c-11e4-8ed6-0800200c9a66", "name" : "Experiment 1", "audience" : "all", "device_types": [ "ios", "android" ], "variants" : [{ "push" : { "notification" : { "alert" : "message 1" } }, "id" : 0, }, { "push" : { "notification" : { "alert" : "message 2" } }, "id" : 1, }] } } ``` ```python from urbanairship import BasicAuthClient, ABTest client = BasicAuthClient( key='', secret='' ) ab_test = ABTest(client) response = ab_test.lookup(experiment_id='0f7704e9-5dc0-4f7d-9964-e89055701b0a') ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') ab_test = UA::AbTest.new(client: airship) ab_test.experiment_id = '0f7704e9-5dc0-4f7d-9964-e89055701b0a' ab_test.lookup_ab_test ``` --- ## Scheduled experiment listing {#getscheduledexperiments} List scheduled experiments in order, from closest to the current [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) to farthest (i.e., the experiments scheduled to occur soonest will appear at the top of the list). Responses are paginated, using optional `limit` and `offset` parameters. [Jump to examples ↓](#getscheduledexperiments-examples) ### `GET /api/experiments/scheduled` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `limit` | `integer` | | Positive maximum number of elements to return per page. The default `limit` is 10 entries with a maximum of 100 entries. Min: 1 Max: 100 | | `offset` | `integer` | | A zero-based integer offset into the result set. If you do not use an offset, results will begin with experiment scheduled to begin at the soonest [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format). If the `offset` is greater than the number of queryable experiments, the result set will be empty. | **Responses** **`200`** Returned on success, with the JSON representation of the experiments in the body of the response. Response body: **Content-Type:** `application/json` - **`count`** `integer` The number of items in this page of results. - **`experiments`** `array` <[Experiment object]({{< ref "/developer/rest-api/ua/schemas/others/" >}}#experimentobject)> Experiments listed by `scheduled_time` in ascending time order. The number of objects will never exceed the `limit` specified in the request. - **`next_page`** `string` A relative URL leading to the next page of results. If there are no more results, next_page is absent. - **`ok`** `boolean` **REQUIRED** If true, the operation completed successfully and returns an expected result set. - **`total_count`** `integer` The total number of results. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/experiments/scheduled HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Length: 123 Data-Attribute: experiments Content-Type: application/vnd.urbanairship+json; version=3 { "ok": "true", "count": 2, "total_count": 2, "experiments": [ { "id": "0f7704e9-5dc0-4f7d-9964-e89055701b0a", "name": "Experiment 1", "audience": "all", "device_types": [ "ios", "android" ], "variants": [ { "id": 0, "schedule": { "scheduled_time": "2020-11-17T20:58:00Z" }, "push": { "notification": { "alert": "message 1" } } }, { "id": 1, "schedule": { "scheduled_time": "2020-11-17T20:58:00Z" }, "push": { "notification": { "alert": "message 2" } } } ] }, { "id": "29705c10-5951-11e4-8ed6-0800200c9a66", "name": "Experiment 2", "audience": "all", "device_types": [ "ios", "android" ], "variants": [ { "id": 0, "schedule": { "scheduled_time": "2020-12-17T20:58:00Z" }, "push": { "notification": { "alert": "message 1" } } }, { "id": 1, "schedule": { "scheduled_time": "2020-12-17T20:58:00Z" }, "push": { "notification": { "alert": "message 2" } } } ] } ] } ``` ```python from urbanairship import ( BasicAuthClient, ABTest ) client = BasicAuthClient( key='', secret='' ) ab_test = ABTest(client) response = ab_test.list_scheduled_experiment() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') ab_test = UA::AbTest.new(client: airship) ab_test.list_scheduled_ab_test ``` --- ## Validate experiment {#validateexperiment} Accepts the same range of payloads as `/api/experiments`, but only parses and validates the payload without creating the experiment. This does the same amount of validation as the creation endpoint, including platform-specific validation, e.g., APNs byte limit checks. While this operation ensures the experiment is technically valid, it does not guarantee that a resulting push will succeed. An experiment may validate and still fail to be delivered. For example, you may have a valid experiment with no devices in your audience. [Jump to examples ↓](#validateexperiment-examples) ### `POST /api/experiments/validate` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) **Request body** A single experiment object. **Content-Type:** `application/json` [Experiment object]({{< ref "/developer/rest-api/ua/schemas/others/" >}}#experimentobject) **Responses** **`200`** The experiment is valid. Response body: **Content-Type:** `application/json` - **`ok`** `boolean` **REQUIRED** If true, the operation completed successfully and returns an expected response. - **`operation_id`** `string` A unique string that represents a single API call, used to identify the operation or side effects in reporting and troubleshooting logs. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/experiments/validate HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "name": "Experiment 1", "audience": {"tag": "earlyBirds"}, "device_types": [ "ios", "android" ], "variants": [ { "push": { "notification": { "alert": "message 1" } } }, { "push": { "notification": { "alert": "message 2" } } } ] } ``` ```http HTTP/1.1 200 OK Content-Length: 123 Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : "true", "operation_id" : "03ca94a3-2b27-42f6-be7e-41efc2612cd4" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); Schedule schedule = Schedule.newBuilder() .setScheduledTimestamp(DateTime.now().plusMinutes(5)) .build(); Variant variantOne = Variant.newBuilder() .setPushPayload(VariantPushPayload.newBuilder() .setNotification(Notification.newBuilder() .setAlert("message 1") .build() ) .build()) .setSchedule(schedule) .build(); Variant variantTwo = Variant.newBuilder() .setPushPayload(VariantPushPayload.newBuilder() .setNotification(Notification.newBuilder() .setAlert("message 2") .build() ) .build()) .setSchedule(schedule) .build(); Experiment experiment = Experiment.newBuilder() .setName("Experiment 1") .setDescription("Testing description") .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS, DeviceType.ANDROID)) .setAudience(Selectors.tag("earlyBirds")) .addVariant(variantOne) .addVariant(variantTwo) .build(); ExperimentRequest request = ExperimentRequest.newRequest(experiment).setValidateOnly(true); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, ABTest, Experiment, Variant ) from urbanairship.push import notification client = BasicAuthClient( key='', secret='' ) # Create push notifications for variants push_1 = notification(alert='message 1') push_2 = notification(alert='message 2') # Create variants variants = [ Variant(push=push_1), Variant(push=push_2) ] # Create experiment experiment = Experiment( audience={'tag': 'earlyBirds'}, device_types=['ios', 'android'], variants=variants, name='Experiment 1' ) # Validate experiment ab_test = ABTest(airship=client) response = ab_test.validate(experiment=experiment) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') variant_one = UA::Variant.new(client: airship) variant_one.push = { "notification": { "alert": "message 1" } } variant_two = UA::Variant.new(client: airship) variant_two.push = { "notification": { "alert": "message 2" } } experiment = UA::Experiment.new(client: airship) experiment.name = 'Experiment 1' experiment.description = 'Example experiment' experiment.audience = UA.tag('earlyBirds') experiment.device_types = ['ios','android'] experiment.variants << variant_one.payload experiment.variants << variant_two.payload ab_test = UA::AbTest.new(client: airship) ab_test.experiment_object = experiment.payload ab_test.validate_ab_test ``` --- # Attribute Lists > Define and manage attribute lists; upload corresponding attribute data in CSV format. ## Create Attributes list {#createattributelist} Create a new Attributes list by defining it in the Airship system. The body of the request contains the name, description, and optional metadata for the list. After you define a list, you populate it with a call to the [Upload Attribute List](/docs/developer/rest-api/ua/operations/attribute-lists/#uploadattributelist) endpoint. [Jump to examples ↓](#createattributelist-examples) ### `POST /api/attribute-lists` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Request body** **Content-Type:** `application/json` - **`description`** `string` An optional description for the list. Min length: 1, Max length: 1000 - **`extra`** `object` An optional JSON map of up to 100 key-value (string-to-string) pairs associated with the list. Keys in this object have a 64-character maximum; values can be up to 1,024 characters. - **`name`** `string` **REQUIRED** The name of the list, consists of up to 64 URL-safe characters. The name is how the list is identified, so it should be unique and memorable. Note: Since the `name` portion of the URL may represent any Unicode string, it must be encoded properly as a URI path component. The `encodeURIComponent` function in JavaScript can be used. The list name must include a prefix that determines how empty values are handled: - Lists with `ua_attributes_` prefix: Empty or null values are ignored, preserving any existing attribute values not explicitly set in the CSV. This mode is useful for making partial updates to a user's attributes without affecting others. - Lists with `ua_attributes_snapshot_` prefix: Empty or null values trigger removing those attributes from the user. This mode is useful for synchronizing attribute states with external systems, ensuring the attributes in the CSV exactly match the user's attributes. Min length: 1, Max length: 64 **Responses** **`201`** The list was created successfully. Response headers: | Name | Type | Description | |------|------|-------------| | `Location` | `string` | The URI of the list, used for later updates. | Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`409`** The request conflicts with another request. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/attribute-lists HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "name": "ua_attributes_my_new_list", "description": "First of many attributes lists!", "extra": { "filename": "attributes.csv", "source": "CRM" } } ``` ```http HTTP/1.1 201 Created Content-Type: application/json Location: https://go.urbanairship.com/api/attribute-lists/ua_attributes_my_new_list { "ok" : true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); AttributeListsCreateRequest attributeListsCreateRequest = AttributeListsCreateRequest.newRequest("ua_attributes_list") .setDescription("ua_attributes_list") .addExtra("filename", "attributes.csv") .addExtra("source","crm"); Response response = client.execute(attributeListsCreateRequest); ``` ```python from urbanairship import ( BasicAuthClient, AttributeList ) client = BasicAuthClient( key='', secret='' ) attribute_list = AttributeList( client=client, list_name="ua_attributes_my_new_list", description="First of many attributes lists!", extra={ "filename": "attributes.csv", "source": "CRM" } ) attribute_list.create() ``` --- ## Download list errors {#getattributelisterrors} During processing, after a list is uploaded, errors can occur. Depending on the type of list processing, an error file may be created, showing a user exactly what went wrong. [Jump to examples ↓](#getattributelisterrors-examples) ### `GET /api/attribute-lists/{list_name}/errors` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `list_name` | `string` | Required | The name of the list. | **Responses** **`200`** The response will contain the errors found during list processing. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [List response object]({{< ref "/developer/rest-api/ua/schemas/others/" >}}#listobject) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/attribute-lists/ua_attributes_list/errors HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+csv; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: text/csv 8b4de669-16f1-4e71-9a1f-0c62a8235a65,ERROR,"Unable to parse number: forty-two" d5ebe607-a3e6-4601-b97e-83ec604223fe,ERROR,"Unable to parse date: monday" ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); AttributeListsErrorsRequest attributeListsErrorsRequest = AttributeListsErrorsRequest.newRequest("ua_attributes_list"); Response response = client.execute(attributeListsErrorsRequest); ``` ```python from urbanairship import ( BasicAuthClient, AttributeList ) client = BasicAuthClient( key='', secret='' ) attribute_list = AttributeList( client=client, list_name="ua_attributes_list", description="example list", ) errors = attribute_list.get_errors() ``` --- ## Retrieve lists {#getattributelistmetadata} Retrieve information about all Attributes lists. This call returns a list of metadata that will not contain the actual lists of users. [Jump to examples ↓](#getattributelistmetadata-examples) ### `GET /api/attribute-lists` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Responses** **`200`** Lists metadata retrieved successfully. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`lists`** `array` <[List response object]({{< ref "/developer/rest-api/ua/schemas/others/" >}}#listobject)> An array of list objects. - **`ok`** `boolean` Success. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/attribute-lists HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Data-Attribute: lists Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "lists": [ { "name": "ua_attributes_my_list", "description": "My first list", "extra": { "filename": "list.csv", "source": "crm" }, "created": "2020-05-13T21:41:25", "last_updated": "2020-05-13T21:45:17", "channel_count": 0, "error_path": "https://go.urbanairship.com/api/attribute-lists/ua_attributes_my_list/errors", "status": "ready" }, { "name": "ua_attributes_another_list", "description": "My second list", "extra": { "filename": "list2.csv", "source": "api" }, "created": "2020-05-14T21:41:25", "last_updated": "2020-05-14T21:45:17", "channel_count": 0, "error_path": "https://go.urbanairship.com/api/attribute-lists/ua_attributes_another_list/errors", "status": "ready" } ] } ``` ```python from urbanairship import ( BasicAuthClient, AttributeList ) client = BasicAuthClient( key='', secret='' ) listing = AttributeList.list(airship=client) listing.json() ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); AttributeListsListingRequest attributeListsListingRequest = AttributeListsListingRequest.newRequest(); Response response = client.execute(attributeListsListingRequest); ``` --- ## Upload Attribute list {#uploadattributelist} Upload a CSV that will set Attribute values on the specified channels or Named Users. CSV guidelines: - The first entry in the uploaded CSV must be a header row. The first field must be one of the following identifier types: `channel_id`, `msisdn`, `email_address`, or `named_user`. - Only one identifier type is allowed per file unless the identifier type name matches a custom Attribute schema for the associated app key. - You must include both `msisdn` and `sms_sender` columns when targeting SMS or MMS channel types. See example to the right. - Uploads must be newline-delimited identifiers (text/CSV) as described in RFC 4180, with commas as the delimiter, optionally double-quoted values, UTF-8 encoded, and with CRLF or LF line separators. Required column headers per identifier type: | Target type | Required column headers | |------------------|------------------------------------------------------------------------------------------| | iOS | `channel_id` | | Android | `channel_id` | | Named User | `named_user` | | Web | `channel_id` | | Email | `email_address` | | Open Channel | `channel_id` | | SMS |
  • `msisdn` (numeric and no leading 0)
  • `sms_sender` (numeric, e.g., `1234`)
| | MMS |
  • `msisdn` (numeric and no leading 0)
  • `sms_sender` (numeric, e.g., `1234`)
| Optional Fields: Opt-in dates can optionally be set for new channels when the identifier is an `email_address` or `msisdn`. | Target type | Optional column headers | |-----------------|------------------------------------------------------------------------------------------| | SMS | `ua_opted_in` (UTC Timestamp) | | MMS | `ua_opted_in` (UTC Timestamp) | | Email |
  • `ua_transactional_opted_in` (UTC Timestamp)
  • `ua_commercial_opted_in` (UTC Timestamp)
| [Jump to examples ↓](#uploadattributelist-examples) ### `PUT /api/attribute-lists/{list_name}/csv` {{< note >}} A list can contain a maximum of 10 million rows and 101 columns: one identifier column and 100 Attribute or internal header columns. `Content-Encoding: gzip` is supported and recommended on this endpoint to reduce network traffic. {{< /note >}} {{< warning >}} If your upload times out due to a poor connection, you must re-upload the list from scratch. Because we want to ensure that the entirety of a given list is successfully uploaded, we do not support partial list uploads. {{< /warning >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `list_name` | `string` | Required | The `name` of the list you want to upload. | **Request body** **Content-Type:** `text/csv` Type: `string` **Responses** **`202`** The request has been accepted for processing. Response body: **Content-Type:** `application/json` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** Bad Request. Parsing or validating the request failed. | Error code | Description | |---|---| | 40002 | CSV contains too many identifiers | | 40003 | CSV header contains too many columns | | 40013 | CSV header's first field must be an identifier | | 40014 | CSV header contains an unknown Attribute name | | 40015 | CSV header contains duplicate Attribute names | | 40017 | CSV header contains duplicate column names | | 40018 | CSV header does not contain required column for identifier type | Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Upload Attribute list example* ```http PUT /api/attribute-lists/ua_attributes_list/csv HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: text/csv channel_id,Magic Score,Preferred Sport c543f3a3-bc1d-4830-8dee-7532c6a23b9a,100,Basketball 6ba360a0-1f73-4ee7-861e-95f6c1ed6410,,Basketball 15410d17-687c-46fa-bbd9-f255741a1523,2,Football c2c64ef7-8f5c-470e-915f-f5e3da04e1df,22.1,Rugby ``` *Upload Attribute Snapshot list example* ```http PUT /api/attribute-lists/ua_attributes_snapshot_list/csv HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: text/csv channel_id,Magic Score,Preferred Sport,Favorite Team c543f3a3-bc1d-4830-8dee-7532c6a23b9a,100,Basketball,Lakers 6ba360a0-1f73-4ee7-861e-95f6c1ed6410,,,, 15410d17-687c-46fa-bbd9-f255741a1523,2,Football, c2c64ef7-8f5c-470e-915f-f5e3da04e1df,22.1,,Patriots # In this example using a Snapshot CSV: # - First user has all attributes set # - Second user has all attributes removed (empty values) # - Third user has Magic Score and Preferred Sport set, but Favorite Team removed # - Fourth user has Magic Score and Favorite Team set, but Preferred Sport removed ``` ```python from urbanairship import ( BasicAuthClient, AttributeList ) client = BasicAuthClient( key='', secret='' ) # For standard attribute lists, use ua_attributes_ prefix standard_list = AttributeList( client=client, list_name="ua_attributes_list", description="example standard list", ) standard_list.upload(file_path="path/to/standard_file.csv") # For attributesnapshot lists, use ua_attributes_snapshot_ prefix snapshot_list = AttributeList( client=client, list_name="ua_attributes_snapshot_list", description="example snapshot list", ) snapshot_list.upload(file_path="path/to/snapshot_file.csv") ``` *Upload Attribute list for SMS example* ```http PUT /api/attribute-lists/ua_attributes_list/csv HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: text/csv msisdn,sms_sender,firstName 5035556789,18588675309,Jane 4155551212,18588675309,Rory ``` ```http HTTP/1.1 202 Accepted Content-Type: application/json { "ok" : true } ``` ```python from urbanairship import ( BasicAuthClient, AttributeList ) client = BasicAuthClient( key='', secret='' ) attribute_list = AttributeList( client=client, list_name="ua_attributes_list", description="example list", ) attribute_list.upload(file_path="path/to/sms_file.csv") ``` --- # Automation > Manage Automated notifications using the `/api/pipelines` endpoints. {{< note >}} In the dashboard UI, we refer to pipelines as *Automation* or *Automated Messages*. {{< /note >}} ## Create pipeline (automated message) {#createpipeline} Create one or more pipelines. You can provide a single [pipeline object](/docs/developer/rest-api/ua/schemas/pipeline-objects/#pipelineobject) or an array of [pipeline objects](/docs/developer/rest-api/ua/schemas/pipeline-objects/#pipelineobject). [Jump to examples ↓](#createpipeline-examples) ### `POST /api/pipelines` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): pln **Request body** A single [pipeline object](/docs/developer/rest-api/ua/schemas/pipeline-objects/#pipelineobject) or an array of pipeline objects. **Content-Type:** `application/json` **One of:** - [Pipeline object]({{< ref "/developer/rest-api/ua/schemas/pipeline-objects/" >}}#pipelineobject) A pipeline object encapsulates the complete set of objects that define an Automation pipeline: Triggers, Outcomes, and metadata. At least one of `immediate_trigger` or `historical_trigger` must be supplied. - `array` **Responses** **`201`** If creating more than one pipeline, pipeline URIs are returned in the same order as the pipeline objects in the request. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` Success. - **`operation_id`** `string` A unique string identifying a single API call. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`pipeline_urls`** `array[string]` An array of of pipeline URIs. If more than one entity was included in the request, the URIs will be in the same order as the objects in the request. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`409`** The request conflicts with another request. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`413`** Returned when the request is too large to be processed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/pipelines HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "name":"The Darkest Pipeline", "enabled":true, "immediate_trigger":"first_open", "outcome":{ "push":{ "audience":"triggered", "device_types":[ "ios", "android", "web" ], "notification":{ "alert":"Cool goatee, Abed" } } }, "timing":{ "delay":{ "seconds":7200 }, "schedule":{ "type":"local", "miss_behavior":"wait", "dayparts":[ { "days_of_week":[ "thursday" ], "allowed_times":[ { "preferred":"21:30:00" } ] } ] } } } ``` ```http HTTP/1.1 201 Created Content-Length: 123 Data-Attribute: pipeline_urls Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "86ad9239-373d-d0a5-d5d8-04fed18f79bc", "pipeline_urls": [ "https://go.urbanairship/api/pipelines/86ad9239-373d-d0a5-d5d8-04fed18f79bc" ] } ``` ```python from urbanairship import ( BasicAuthClient, Automation ) from urbanairship.automation.pipeline import Pipeline client = BasicAuthClient( key='', secret='' ) automation = Automation(client) pipeline = Pipeline( name='The Darkest Pipeline', enabled=True, immediate_trigger='first_open', outcome={ 'push': { 'audience': 'triggered', 'device_types': ['ios', 'android', 'web'], 'notification': {'alert': 'Cool goatee, Abed'} } }, timing={ 'delay': {'seconds': 7200}, 'schedule': { 'type': 'local', 'miss_behavior': 'wait', 'dayparts': [{ 'days_of_week': ['thursday'], 'allowed_times': [ {'preferred': '21:30:00'} ] }] } } ) response = automation.create(pipeline.payload) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') pipeline = UA::Pipeline.new(client: airship) pipeline.enabled = true pipeline.immediate_trigger = "first_open" pipeline.outcome = { "push": { "audience": "triggered", "device_types": ['ios','android','web'], "notification": { "alert": "Cool goatee, Abed" } } } automation = UA::Automation.new(client: airship) automation.pipeline_object = pipeline.payload details = automation.create_automation puts(details) ``` --- ## Delete pipeline {#deletepipeline} Delete a pipeline. [Jump to examples ↓](#deletepipeline-examples) ### `DELETE /api/pipelines/{pipeline_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): pln **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `pipeline_id` | `string` | Required | The pipeline you want to return or modify. | **Responses** **`204`** An API request was successful, but there is no response body to return. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http DELETE /api/pipelines/0f927674-918c-31ef-51ca-e96fdd234da4 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 204 No Content ``` ```python from urbanairship import ( BasicAuthClient, Automation ) from urbanairship.automation.pipeline import Pipeline client = BasicAuthClient( key='', secret='' ) automation = Automation(client) response = automation.delete('0f927674-918c-31ef-51ca-e96fdd234da4') ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') automation = UA::Automation.new(client: airship) automation.pipeline_id = '0f927674-918c-31ef-51ca-e96fdd234da4' automation.delete_automation ``` --- ## Individual pipeline lookup {#getpipeline} Fetch a single pipeline resource. Returns an array containing a single pipeline object in the `pipeline` attribute. [Jump to examples ↓](#getpipeline-examples) ### `GET /api/pipelines/{pipeline_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): pln **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `pipeline_id` | `string` | Required | The pipeline you want to return or modify. | **Responses** **`200`** Returned on success, with the JSON representation of the pipeline in the body of the response. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`next_page`** `string` An URI that points to the next page of pipelines. The page size is specified by the `limit` parameter and the start point by the `start` parameter. If there are no more pipelines for a next page we omit the next page link. - **`ok`** `boolean` Success. - **`operation_id`** `string` A unique string identifying a single API call. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`pipeline_ids`** `array[string]` An array of pipeline IDs. - **`pipeline_urls`** `array[string]` An array of of pipeline URIs. If more than one entity was included in the request, the URIs will be in the same order as the objects in the request. - **`pipelines`** `array` <[Pipeline object]({{< ref "/developer/rest-api/ua/schemas/pipeline-objects/" >}}#pipelineobject)> A list of pipeline objects. - **`prev_page`** `string` An URI that points to the previous page of pipelines. The page size is specified by the `limit` parameter and the start point by the `start` parameter. If there are no more pipelines for a previous page we omit the previous page link. - **`total_count`** `integer` The total count of pipelines. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/pipelines/4d3ff1fd-9ce6-5ea4-5dc9-5ccbd38597f4 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "pipeline": { "creation_time": "2020-02-14T19:19:19", "enabled": true, "immediate_trigger": { "tag_added": "new_customer" }, "last_modified_time": "2020-03-01T12:12:54", "name": "New customer", "outcome": { "push": { "audience": "triggered", "device_types": [ "ios", "android" ], "notification": { "alert": "Hello new customer!" } } }, "status": "live", "uid": "86ad9239-373d-d0a5-d5d8-04fed18f79bc", "url": "https://go.urbanairship/api/pipelines/86ad9239-373d-d0a5-d5d8-04fed18f79bc" } } ``` ```python from urbanairship import ( BasicAuthClient, Automation ) from urbanairship.automation.pipeline import Pipeline client = BasicAuthClient( key='', secret='' ) automation = Automation(client) pipeline = automation.lookup('4d3ff1fd-9ce6-5ea4-5dc9-5ccbd38597f4') ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') automation = UA::Automation.new(client: airship) automation.pipeline_id = '4d3ff1fd-9ce6-5ea4-5dc9-5ccbd38597f4' automation.lookup_automation ``` --- ## List deleted pipelines {#getdeletedpipelines} Produces a list of all deleted pipelines starting with the most recently deleted entry. [Jump to examples ↓](#getdeletedpipelines-examples) ### `GET /api/pipelines/deleted` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): pln **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `start` | `string` | | The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) of the starting element for paginating results. | | `limit` | `integer` | | The maximum number of elements to return. | **Responses** **`200`** Returns an array of deleted pipeline objects. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` Success. - **`pipelines`** `array[object]` **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/pipelines/deleted/ HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "pipelines": [ { "deletion_time": "2020-03-31T20:54:45", "pipeline_id": "0sdicj23-fasc-4b2f-zxcv-0baf934f0d69" }, { "..." } ] } ``` ```python from urbanairship import ( BasicAuthClient, Automation ) from urbanairship.automation.pipeline import Pipeline client = BasicAuthClient( key='', secret='' ) automation = Automation(client) response = automation.list_deleted_automations() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') automation = UA::Automation.new(client: airship) automation.start = 2020-11-23 automation.list_deleted_automations ``` --- ## List existing pipelines {#getpipelines} List existing pipelines. Pipelines are ordered by `creation_date` from newest to oldest. [Jump to examples ↓](#getpipelines-examples) ### `GET /api/pipelines` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): pln **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `limit` | `integer` | | The maximum number of results to return. This is effectively the page size for the response. No default limit. For maximum performance, set your limit between 25 and 100. Min: 1 | | `enabled` | `boolean` | | If true, limits the listing to enabled pipelines (`"enabled": true`). If false or omitted, lists all pipelines, whether `enabled` is `true` or `false`. | | `offset` | `integer` | | The first result you want to return. This parameter assists in pagination. | **Responses** **`200`** Returned on success, with a JSON representation of pipelines matching your query parameters. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`next_page`** `string` An URI that points to the next page of pipelines. The page size is specified by the `limit` parameter and the start point by the `start` parameter. If there are no more pipelines for a next page we omit the next page link. - **`ok`** `boolean` Success. - **`operation_id`** `string` A unique string identifying a single API call. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`pipeline_ids`** `array[string]` An array of pipeline IDs. - **`pipeline_urls`** `array[string]` An array of of pipeline URIs. If more than one entity was included in the request, the URIs will be in the same order as the objects in the request. - **`pipelines`** `array` <[Pipeline object]({{< ref "/developer/rest-api/ua/schemas/pipeline-objects/" >}}#pipelineobject)> A list of pipeline objects. - **`prev_page`** `string` An URI that points to the previous page of pipelines. The page size is specified by the `limit` parameter and the start point by the `start` parameter. If there are no more pipelines for a previous page we omit the previous page link. - **`total_count`** `integer` The total count of pipelines. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/pipelines/ HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "pipelines": [ { "creation_time": "2020-03-20T18:37:23", "enabled": true, "immediate_trigger": { "tag_added": { "tag": "bought_shoes" } }, "last_modified_time": "2020-03-20T19:35:12", "name": "Shoe buyers", "outcome": { "push": { "audience": "triggered", "device_types": [ "android" ], "notification": { "alert": "So you like shoes, huh?" } } }, "status": "live", "uid": "3987f98s-89s3-cx98-8z89-89adjkl29zds", "url": "https://go.urbanairship.com/api/pipelines/3987f98s-89s3-cx98-8z89-89adjkl29zds" }, { "..." } ] } ``` ```python from urbanairship import ( BasicAuthClient, Automation ) from urbanairship.automation.pipeline import Pipeline client = BasicAuthClient( key='', secret='' ) automation = Automation(client) for pipeline in automation.list_automations(): print(pipeline) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') automation = UA::Automation.new(client: airship) automation.limit = 5 automation.list_automations ``` --- ## List filtered pipelines {#getfilteredpipelines} Lists all pipelines, which fulfill the provided filter criteria. Returns a response container, which contains an array of pipeline objects in the `pipelines` attribute. The response container also provides total count and links to the next page `next_page` and previous page `prev_page`, if applicable. We also always apply a sort order. By default we apply an ascending sort order on the name `name` field, but we also support a sort order on the started date `started_date` field. Pagination is always applied, which means that the pipeline result list is not the complete list of pipelines if the total count is greater than the page limit. ### `GET /api/pipelines/filtered` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): pln **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `start` | `integer` | | Non-negative zero-based index of the starting element for paginating results. Default value 0. Min: 1 | | `limit` | `integer` | | The maximum number of results to return. This is effectively the page size for the response. Min: 1 | | `enabled` | `boolean` | | If true, limits the listing to enabled pipelines. If false or omitted, lists all pipelines, whether `enabled` is `true` or `false`. | | `started_date_mills` | `integer` | | Limits the listing to only pipelines that were started after the specified date in milliseconds. | | `prefix` | `string` | | Search term, which is used as a prefix search term. | | `triggers` | `string` | | 0 or more trigger types. The triggers filter limits the listing of pipelines by the specified trigger types. For example, if you specify `REGION_EXITED` and `REGION_ENTERED`, only pipelines that are associated with region entry and region exit triggers will be shown. If no trigger types are specified, no triggers filter will be applied and all pipelines will be listed. Possible values: `TAG_ADDED`, `TAG_REMOVED`, `FIRST_REG`, `FIRST_OPT_IN`, `ACTIVITY`, `REGION_ENTERED`, `REGION_EXITED`, `CUSTOM_EVENT`, `SUBSCRIPTION_ADDED`, `SUBSCRIPTION_REMOVED` | | `sort` | `string` | | Specifies the field, which should be sorted. Two fields are supported: `name` and `started_date`. If you omit the `sort` parameter, the default value `name` is used. If you provide an unknown field name, we will default to the `name` field. Possible values: `name`, `started_date` | | `order` | `string` | | Specifies the sort order as ascending (`asc`) or descending (`desc`). If you omit the `order` parameter, the default value `asc` is used. Possible values: `asc`, `desc` | **Responses** **`200`** Returned on success, with a JSON representation of pipelines matching your query parameters. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`next_page`** `string` An URI that points to the next page of pipelines. The page size is specified by the `limit` parameter and the start point by the `start` parameter. If there are no more pipelines for a next page we omit the next page link. - **`ok`** `boolean` Success. - **`operation_id`** `string` A unique string identifying a single API call. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`pipeline_ids`** `array[string]` An array of pipeline IDs. - **`pipeline_urls`** `array[string]` An array of of pipeline URIs. If more than one entity was included in the request, the URIs will be in the same order as the objects in the request. - **`pipelines`** `array` <[Pipeline object]({{< ref "/developer/rest-api/ua/schemas/pipeline-objects/" >}}#pipelineobject)> A list of pipeline objects. - **`prev_page`** `string` An URI that points to the previous page of pipelines. The page size is specified by the `limit` parameter and the start point by the `start` parameter. If there are no more pipelines for a previous page we omit the previous page link. - **`total_count`** `integer` The total count of pipelines. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) --- ## List pipelines constraints {#getpipelinesconstraints} Returns an array of cross-pipeline rate limit constraints. These are the rates that the combination of all pipelines for an app may not exceed. [Jump to examples ↓](#getpipelinesconstraints-examples) ### `GET /api/pipelines/constraints` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): pln **Responses** **`200`** Returns an array of cross-pipeline rate limit constraints. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`constraints`** `array[object]` An array of rate objects determining the maximum number of messages each audience member can receive over a period of time. - **`ok`** `boolean` Success. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/pipelines/constraints/ HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "constraints" : [ { "rate" : { "pushes" : 30, "lifetimes" : 1 } }, { "rate" : { "pushes" : 15, "days" : 3 } }, { "rate" : { "pushes" : 4, "hours" : 6 } } ] } ``` --- ## List pipelines limits {#getpipelineslimits} Return the currently configured limits for number of total and active pipelines, as well as the total and active counts. [Jump to examples ↓](#getpipelineslimits-examples) ### `GET /api/pipelines/limits` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): pln **Responses** **`200`** Returns a JSON dictionary in the `limits` attribute. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`limits`** `object` **OBJECT PROPERTIES** - **`active_count`** `integer` An integer indicating the number of pipelines created by the application which are currently enabled. - **`active_limit`** `integer` An integer indicating the total number of active pipelines that the app is allowed to have. - **`total_count`** `integer` An integer indicating the total number of pipelines that currently exist for the application, regardless of their enabled state. - **`total_limit`** `integer` An integer indicating the total number of pipelines that the app is allowed to have, regardless of their enabled state. - **`ok`** `boolean` Success. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/pipelines/limits/ HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "limits" : { "total_limit" : 50, "active_limit" : 20, "total_count" : 23, "active_count" : 7 } } ``` --- ## Update pipeline {#updatepipeline} Update the state of a single pipeline resource. You must include the complete payload from a POST response, with changes you want to make to the resource. You cannot provide a partial payload. If you omit optional fields during this operation that were already set for the pipeline, they will be nullified. [Jump to examples ↓](#updatepipeline-examples) ### `PUT /api/pipelines/{pipeline_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): pln **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `pipeline_id` | `string` | Required | The pipeline you want to return or modify. | **Request body** A single pipeline object or an array of pipeline objects. **Content-Type:** `application/json` [Pipeline object]({{< ref "/developer/rest-api/ua/schemas/pipeline-objects/" >}}#pipelineobject) **Responses** **`200`** Returned if the pipeline has been successfully updated. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`409`** The request conflicts with another request. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`413`** Returned when the request is too large to be processed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http PUT /api/pipelines/0f927674-918c-31ef-51ca-e96fdd234da4 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json; { "enabled": true, "immediate_trigger": { "tag_added": "new_customer" }, "outcome": { "push": { "audience": "triggered", "device_types": [ "ios" ], "notification": { "alert": "Hello new customer!" } } } } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```python from urbanairship import ( BasicAuthClient, Automation ) from urbanairship.automation.pipeline import Pipeline client = BasicAuthClient( key='', secret='' ) automation = Automation(client) pipeline = Pipeline( enabled=True, immediate_trigger={ 'tag_added': 'new_customer' }, outcome={ 'audience': 'triggered', 'device_types': ['ios'], 'notification': notification(alert='Hello new customer!') } ) response = automation.update( pipeline_id='0f927674-918c-31ef-51ca-e96fdd234da4', pipeline=pipeline.payload ) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') pipeline = UA::Pipeline.new(client: airship) pipeline.enabled = true pipeline.immediate_trigger = { "tag_added": { "tag": "new_customer", "group": "crm" } } pipeline.outcome = { "push": { "audience": "triggered", "device_types": ["ios"], "notification": { "alert": "Hello new customer!" } } } automation = UA::Automation.new(client: airship) automation.pipeline_id = '0f927674-918c-31ef-51ca-e96fdd234da4' automation.pipeline_object = pipeline.payload automation.update_automation ``` --- ## Update pipelines constraints {#updatepipelineconstraints} Update the pipelines constraints. [Jump to examples ↓](#updatepipelineconstraints-examples) ### `PUT /api/pipelines/constraints` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): pln **Request body** An array of no more than 5 cross-pipeline rate limit constraints. **Content-Type:** `application/json` - **`constraints`** `array[object]` An array of rate objects determining the maximum number of messages each audience member can receive over a period of time. Max items: 5 - **`ok`** `boolean` Success. **Responses** **`200`** Everything worked as expected. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http PUT /api/pipelines/constraints/ HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "constraints" : [ { "rate" : { "pushes" : 15, "days" : 3 } }, { "rate" : { "pushes" : 4, "hours" : 6 } } ] } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` --- ## Validate pipeline {#validatepipeline} This endpoint accepts the same range of payloads as a `POST` to `/api/pipelines`, but only parses and validates the payload, without creating the pipeline. The body of the request must be a single pipeline object or an array of pipeline objects. [Jump to examples ↓](#validatepipeline-examples) ### `POST /api/pipelines/validate` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): pln **Request body** A single pipeline object or an array of pipeline objects. **Content-Type:** `application/json` **One of:** - [Pipeline object]({{< ref "/developer/rest-api/ua/schemas/pipeline-objects/" >}}#pipelineobject) A pipeline object encapsulates the complete set of objects that define an Automation pipeline: Triggers, Outcomes, and metadata. At least one of `immediate_trigger` or `historical_trigger` must be supplied. - `array` **Responses** **`200`** Everything worked as expected. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`413`** Returned when the request is too large to be processed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/pipelines/validate HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "name":"The Darkest Pipeline", "enabled":true, "immediate_trigger":"first_open", "outcome":{ "push":{ "audience":"triggered", "device_types":[ "ios", "android" ], "notification":{ "alert":"Cool goatee, Abed" } } }, "timing":{ "delay":{ "seconds":7200 }, "schedule":{ "type":"local", "miss_behavior":"wait", "dayparts":[ { "days_of_week":[ "thursday" ], "allowed_times":[ { "preferred":"21:30:00" } ] } ] } } } ``` ```http HTTP/1.1 200 OK Content-Length: 11 Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```python from urbanairship import ( BasicAuthClient, Automation ) from urbanairship.automation.pipeline import Pipeline client = BasicAuthClient( key='', secret='' ) automation = Automation(client) pipeline = Pipeline( name='The Darkest Pipeline', enabled=True, immediate_trigger='first_open', outcome={ 'push': { 'audience': 'triggered', 'device_types': ['ios', 'android', 'web'], 'notification': notification(alert='Cool goatee, Abed') } }, timing={ 'delay': {'seconds': 7200}, 'schedule': { 'type': 'local', 'miss_behavior': 'wait', 'dayparts': [{ 'days_of_week': ['thursday'], 'allowed_times': [ {'preferred': '21:30:00'} ] }] } } ) response = automation.validate(pipeline.payload) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') pipeline = UA::Pipeline.new(client: airship) pipeline.enabled = true pipeline.immediate_trigger = "first_open" pipeline.outcome = { "push": { "audience": "triggered", "device_types": ['ios','android','web'], "notification": { "alert": "Cool goatee, Abed" } } } automation = UA::Automation.new(client: airship) automation.pipeline_object = pipeline.payload automation.validate_automation ``` --- # Bulk Sending > Target recipients of a single channel type by providing audience identifiers at send time. Bulk sending supports two methods: * **Upload and Send** targets existing channels by Channel ID across app, web, email, SMS, and Open channels. Upload a CSV of Channel IDs to the [Create bulk send audience](/developer/rest-api/ua/operations/bulk-sending/#bulkuploadcreateandsendplatform) endpoint to obtain a `bulk_id`, and then send your message using the [Send message with bulk ID](/developer/rest-api/ua/operations/bulk-sending/#bulksendpush) or [Schedule message with bulk ID](/developer/rest-api/ua/operations/bulk-sending/#schedulebulksendpush) endpoint. * **Create and Send** sends to email addresses, MSISDNs, or Open channel addresses. Unknown identifiers are registered as new channels. * For smaller audiences, use the [Create and Send a message](/developer/rest-api/ua/operations/bulk-sending/#createandsend) or [Schedule a Create and Send message](/developer/rest-api/ua/operations/bulk-sending/#schedulecreateandsendoperations) endpoints to provide email addresses, MSISDNs, or Open channel addresses in an array. * For larger audiences, upload identifiers in CSV format to the [Create bulk send audience](/developer/rest-api/ua/operations/bulk-sending/#bulkuploadcreateandsendplatform) endpoint to obtain a `bulk_id`, and then send your message using the [Create and Send a message](/developer/rest-api/ua/operations/bulk-sending/#createandsend) or [Schedule a Create and Send message](/developer/rest-api/ua/operations/bulk-sending/#schedulecreateandsendoperations) endpoint. See the [Bulk sending](/guides/audience/segmentation/bulk-sending/) guide for more information. ## Create and Send a message {#createandsend} Send messages to email addresses, MSISDNs, or Open channel addresses. Unknown identifiers are registered as new channels. This endpoint supports two audience methods: - `create_and_send` array: For smaller audiences, provide email addresses, MSISDNs, or Open channel addresses directly in the request. - `bulk_id`: For larger audiences, upload a CSV using the [Create bulk send audience](/docs/developer/rest-api/ua/operations/bulk-sending/#bulkuploadcreateandsendplatform) endpoint to obtain a `bulk_id`, then reference it in this request. Existing channels that are `opted_in` or have a newer `opted_in` value in the payload receive the message but are not re-registered. You cannot update `opted_in` values for existing channels through this endpoint. Note: This endpoint also accepts Channel IDs for app or web via `bulk_id`, but this works identically to [Send message with bulk ID](/docs/developer/rest-api/ua/operations/bulk-sending/#bulksendpush). [Jump to examples ↓](#createandsend-examples) ### `POST /api/create-and-send` {{< warning >}} Duplicate addresses in the `create_and_send` array might receive redundant notifications or fewer notifications than expected. You should remove duplicate addresses from your request before sending a Create and Send message. {{< /warning >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): psh **Request body** **Content-Type:** `application/json` **One of:** - [Create and Send to email channels]({{< ref "/developer/rest-api/ua/schemas/create-and-send/" >}}#email) The payload for a Create and Send operation to email channels. When sending to email channels, `device_types` must be set to `email`. - [Create and Send to SMS channels]({{< ref "/developer/rest-api/ua/schemas/create-and-send/" >}}#sms) The payload for a Create and Send operation to SMS channels. When sending to SMS channels, `device_types` must be set to `sms`. - [Create and Send MMS notification]({{< ref "/developer/rest-api/ua/schemas/create-and-send/" >}}#mms) The payload for a Create and Send operation that sends a multimedia payload (MMS) to SMS channels. When sending an MMS payload, `device_types` must be set to `mms`. - [Create and Send to open channels]({{< ref "/developer/rest-api/ua/schemas/create-and-send/" >}}#open) The payload for a Create and Send operation to open channels. When sending to open channels, the `device_type` must be set to `open::`. **Responses** **`202`** Because this operation sends messages, a successful response is nearly identical to a `/api/push` response. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`content_urls`** `array[string]` An array of URLs where the push payload contains a landing page action. Min items: 0, Max items: 100 - **`localized_ids`** `array[string]` An array of identifiers used for reporting. Each ID represents a localized message (push object with `localizations` array). - **`message_ids`** `array[string]` An array of message IDs, each uniquely identifying a Message Center message. - **`ok`** `boolean` Success. - **`operation_id`** `string` A unique string identifying the operation, useful for reporting and troubleshooting. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`push_ids`** `array[string]` An array of push IDs, each uniquely identifying a push. Min items: 1, Max items: 100 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`413`** Returned when the request is too large to be processed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example Create and Send a message for email* ```http POST /api/create-and-send HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "create_and_send" : [ { "ua_address": "new@example.com", "ua_commercial_opted_in": "2020-11-29T10:34:22", "ua_open_tracking_opted_in": "2022-11-02T10:35:00", "ua_click_tracking_opted_in": "2022-11-02T10:36:00" }, { "ua_address" : "ben@example.com", "ua_commercial_opted_in": "2020-11-29T12:45:10", "ua_open_tracking_opted_out": "2022-11-02T10:35:00", "ua_click_tracking_opted_out": "2022-11-02T10:36:00" } ] }, "device_types" : [ "email" ], "notification" : { "email": { "subject": "Welcome to the Winter Sale! ", "html_body": "

Seasons Greetings

Check out our winter deals!

Unsubscribe

", "plaintext_body": "Greetings! Check out our latest winter deals! [[ua-unsubscribe href=\"http://unsubscribe.urbanairship.com/email/success.html\"]]", "message_type": "commercial", "sender_name": "Airship", "sender_address": "team@airship.com", "reply_to": "no-reply@airship.com", "click_tracking": false, "open_tracking": false } }, "campaigns": { "categories": ["winter sale", "west coast"] } } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); String htmlBodyString = "

Seasons Greetings

Check out our winter deals!

Unsubscribe

"; String plaintextBodyString = "Greetings! Check out our latest winter deals! [[ua-unsubscribe href=\"http://unsubscribe.urbanairship.com/email/success.html\"]]"; EmailChannel newChannel = EmailChannel.newBuilder() .setAddress("new@example.com") .setCommertialOptedIn(DateTime.parse("2020-11-29T10:34:22Z")) .build(); EmailChannel benChannel = EmailChannel.newBuilder() .setAddress("ben@example.com") .setTransactionalOptedIn(DateTime.parse("2020-11-29T12:45:10Z")) .build(); CreateAndSendAudience audience = new CreateAndSendAudience(EmailChannels.newBuilder() .addChannel(newChannel) .addChannel(benChannel) .build()); CreateAndSendEmailPayload createAndSendEmailPayload = CreateAndSendEmailPayload.newBuilder() .setSubject("Welcome to the Winter Sale! ") .setHtmlBody(htmlBodyString) .setPlaintextBody(plaintextBodyString) .setMessageType(MessageType.TRANSACTIONAL) .setSenderName("Airship") .setSenderAddress("team@airship.com") .setReplyTo("no-reply@airship.com") .build(); Notification notification = Notification.newBuilder() .addDeviceTypeOverride(DeviceType.EMAIL, createAndSendEmailPayload) .build(); Campaigns campaign = Campaigns.newBuilder() .addCategory("winter sale") .addCategory("west coast") .build(); CreateAndSendPayload payload = CreateAndSendPayload.newBuilder() .setAudience(audience) .setNotification(notification) .setCampaigns(campaign) .build(); CreateAndSendRequest request = CreateAndSendRequest.newRequest(payload); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, CreateAndSendPush, email, sms, mms, campaigns ) client = BasicAuthClient(key='', secret='') # Create and Send a message for email push = CreateAndSendPush(client) push.audience = { "create_and_send": [ { "ua_address": "new@example.com", "ua_commercial_opted_in": "2020-11-29T10:34:22" }, { "ua_address": "ben@example.com", "ua_commercial_opted_out": "2020-11-29T12:45:10" }, { "ua_address": "mary@example.com", "ua_email_suppression_state": "BOUNCE" } ] } push.device_types = ["email"] push.notification = email( subject="Welcome to the Winter Sale!", html_body="

Seasons Greetings

Check out our winter deals!

Unsubscribe

", plaintext_body="Greetings! Check out our latest winter deals! [[ua-unsubscribe href=\"http://unsubscribe.urbanairship.com/email/success.html\"]]", message_type="transactional", sender_name="Airship", sender_address="team@airship.com", reply_to="no-reply@airship.com", click_tracking=False, open_tracking=False, attachments=[ {"id": "0e10a6b9-725c-4f6b-9af2-9ef5b31328c0"}, {"id": "5503b5fe-ed69-4609-bef6-6fef0e6e428f"} ] ) push.campaigns = campaigns(categories=["winter sale", "west coast"]) response = push.send() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') email_notification = UA::EmailNotification.new(client: airship) email_notification.bypass_opt_in_level = false email_notification.html_body = "

Seasons Greetings

Check out our winter deals!

Unsubscribe

" email_notification.message_type = 'transactional' email_notification.plaintext_body = 'Greetings! Check out our latest winter deals! [[ua-unsubscribe href=\"http://unsubscribe.urbanairship.com/email/success.html\"]]' email_notification.reply_to = 'no-reply@airship.com' email_notification.sender_address = 'team@airship.com' email_notification.sender_name = 'Airship' email_notification.subject = 'Welcome to the Winter Sale!' override = email_notification.email_override send_it = UA::CreateAndSend.new(client: airship) send_it.addresses = [ { "ua_address": "new@example.com", "ua_commercial_opted_in": "2020-11-29T10:34:22" }, { "ua_address": "ben@example.com", "ua_commercial_opted_in": "2020-11-29T12:45:10" } ] send_it.device_types = [ "email" ] send_it.campaigns = ["winter sale", "west coast"] send_it.notification = email_notification.email_override send_it.create_and_send ``` *Example Create and Send a message for email with stored template* ```http POST /api/create-and-send HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "create_and_send" : [ { "ua_address": "new@example.com", "ua_commercial_opted_in": "2020-11-29T10:34:22", "name": "New Person, Esq.", "location": "City, State" }, { "ua_address" : "ben@example.com", "ua_commercial_opted_in": "2020-11-29T12:45:10", "name": "Ben Wyatt", "location": "Pawnee, IN" } ] }, "device_types": [ "email" ], "notification": { "email": { "bcc": [ "blind@example.com" ], "message_type": "commercial", "reply_to": "no-reply@airship.com", "sender_address": "team@airship.com", "sender_name": "Airship", "template": { "template_id": "9335bb2a-2a45-456c-8b53-42af7898236a" } } } } ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "67c65146-c27f-431f-b54a-83aca694fdd3", "push_ids": [ "c0eead17-333b-4f86-8a42-9fb7be1ed627" ], "message_ids": [], "content_urls": [] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); EmailChannel newChannel = EmailChannel.newBuilder() .setAddress("new@example.com") .setCommertialOptedIn(DateTime.parse("2020-11-29T10:34:22Z")) .build(); EmailChannel benChannel = EmailChannel.newBuilder() .setAddress("ben@example.com") .setTransactionalOptedIn(DateTime.parse("2020-11-29T12:45:10Z")) .build(); CreateAndSendAudience audience = new CreateAndSendAudience(EmailChannels.newBuilder() .addChannel(newChannel) .addChannel(benChannel) .build()); EmailTemplate template = EmailTemplate.newBuilder() .setTemplateId("9335bb2a-2a45-456c-8b53-42af7898236a") .build(); CreateAndSendEmailPayload createAndSendEmailPayload = CreateAndSendEmailPayload.newBuilder() .setEmailTemplate(template) .setMessageType(MessageType.TRANSACTIONAL) .setSenderName("Airship") .setSenderAddress("team@airship.com") .setReplyTo("no-reply@airship.com") .build(); Notification notification = Notification.newBuilder() .addDeviceTypeOverride(DeviceType.EMAIL, createAndSendEmailPayload) .build(); CreateAndSendPayload payload = CreateAndSendPayload.newBuilder() .setAudience(audience) .setNotification(notification) .build(); CreateAndSendRequest request = CreateAndSendRequest.newRequest(payload); Response response = client.execute(request); ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') email_notification = UA::EmailNotification.new(client: airship) email_notification.message_type = 'transactional' email_notification.reply_to = 'no-reply@airship.com' email_notification.sender_address = 'team@airship.com' email_notification.sender_name = 'Airship' email_notification.template_id = "9335bb2a-2a45-456c-8b53-42af7898236a" inline_template = email_notification.email_with_inline_template send_it = UA::CreateAndSend.new(client: airship) send_it.addresses = [ { "ua_address": "new@example.com", "ua_commercial_opted_in": "2020-11-29T10:34:22" }, { "ua_address": "ben@example.com", "ua_commercial_opted_in": "2020-11-29T12:45:10" } ] send_it.device_types = [ "email" ] send_it.notification = inline_template send_it.create_and_send ``` *Example Create and Send with bulk ID for email* ```http POST /api/create-and-send HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "bulk_id": "26425d51-fbab-4ad8-bd5f-9560ee84b087" }, "device_types": [ "email" ], "notification": { "email": { "subject": "Welcome to the Winter Sale!", "html_body": "

Seasons Greetings {{name}}

Check out our winter deals!

Unsubscribe

", "plaintext_body": "Greetings {{name}}! Check out our latest winter deals! [[ua-unsubscribe href=\"http://unsubscribe.urbanairship.com/email/success.html\"]]", "message_type": "commercial", "sender_name": "Airship", "sender_address": "team@airship.com", "reply_to": "no-reply@airship.com" } }, "campaigns": { "categories": ["winter sale", "west coast"] } } ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "67c65146-c27f-431f-b54a-83aca694fdd3", "push_ids": [ "c0eead17-333b-4f86-8a42-9fb7be1ed627" ], "message_ids": [], "content_urls": [] } ``` --- ## Create bulk send audience {#bulkuploadcreateandsendplatform} Upload a CSV to obtain a `bulk_id` for sending messages. The CSV can contain: - Channel IDs for Upload and Send endpoints: [Send message with bulk ID](/docs/developer/rest-api/ua/operations/bulk-sending/#bulksendpush) or [Schedule message with bulk ID](/docs/developer/rest-api/ua/operations/bulk-sending/#schedulebulksendpush) - Email addresses, phone numbers, or Open channel addresses for Create and Send endpoints: [Create and Send a message](/docs/developer/rest-api/ua/operations/bulk-sending/#createandsend) or [Schedule a Create and Send message](/docs/developer/rest-api/ua/operations/bulk-sending/#schedulecreateandsendoperations) See [Bulk sending](/docs/guides/audience/segmentation/bulk-sending/) for CSV formatting requirements. [Jump to examples ↓](#bulkuploadcreateandsendplatform-examples) ### `POST /api/bulk/{platform_name}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `platform_name` | `string` | Required | The audience channel platform. For open platforms, format the `{platform_name}` as `open/{open_platform_name}`. Possible values: `android`, `amazon`, `ios`, `web`, `sms`, `email`, `open_platform_name` | **Request body** **Content-Type:** `text/csv` Type: `string` **Responses** **`200`** The CSV was uploaded successfully and is now being processed. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`bulk_id`** `string` A unique string that identifies the audience provided in the CSV for bulk sending. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`field_names`** `array[string]` A list of the field names found in the CSV. - **`ok`** `boolean` Success. **`400`** Bad Request. Parsing or validating the request failed. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example create bulk send audience request for email* ```http POST /api/bulk/email HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: text/csv ua_address,ua_commercial_opted_in someone@example.com,2024-04-01T18:45:30 else@example.com,2024-04-21T16:13:01 ``` *Example create bulk send audience request for SMS* ```http POST /api/bulk/sms HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: text/csv ua_msisdn,ua_sender,ua_opted_in 15035551212,55555,2024-04-01T18:45:30 15031215555,55555,2024-04-21T16:13:01 ``` *Example create bulk send audience request for email with merge data fields* ```http POST /api/bulk/email HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: text/csv ua_address,ua_commercial_opted_in,name,city someone@example.com,2024-04-01T18:45:30,Joe Someone,Portland else@example.com,2024-04-21T16:13:01,Sir Else,Seattle ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "bulk_id": "26425d51-fbab-4ad8-bd5f-9560ee84b087", "field_names": ["ua_address", "ua_commercial_opted_in", "name", "city"] } ``` *Example create bulk send audience request for email* ```http POST /api/bulk/email HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: text/csv ua_channel_id 26bbfba4-f70a-4093-ab63-38d9123f6b23 89099449-6032-4821-8f1c-fd0892fdc609 ``` *Example create bulk send audience request for email with merge data fields* ```http POST /api/bulk/email HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: text/csv ua_channel_id,name,city 26bbfba4-f70a-4093-ab63-38d9123f6b23,2018-04-01T18:45:30,Joe Someone,Portland 89099449-6032-4821-8f1c-fd0892fdc609,2018-04-21T16:13:01,Sir Else,Seattle ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "bulk_id": "26425d51-fbab-4ad8-bd5f-9560ee84b087", "field_names": ["ua_channel_id", "name", "city"] } ``` *Example create bulk send audience request for open platform* ```http POST /api/bulk/open/rcs HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: text/csv ua_address 17881e35-4dcc-4f72-a017-e5aca8bb85f5 47745e49-099d-48d7-a489-563a2ae7497d 03079fe7-a013-4a22-9c1b-bca350a3e3fb 8a9b3ebc-010c-41c1-9484-6395b201dffe 65fefb71-c38e-4af8-9d6f-ec8bfcefd999 6e6fc2ee-722a-4729-86c3-f6d289373c41 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "bulk_id": "26425d51-fbab-4ad8-bd5f-9560ee84b087", "field_names": ["ua_address"] } ``` *Example create bulk send audience request for open channels* ```http POST /api/bulk/open/rcs HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: text/csv ua_channel_id 26bbfba4-f70a-4093-ab63-38d9123f6b23 89099449-6032-4821-8f1c-fd0892fdc609 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "bulk_id": "26425d51-fbab-4ad8-bd5f-9560ee84b087", "field_names": ["ua_channel_id"] } ``` --- ## Schedule a Create and Send message {#schedulecreateandsendoperations} Schedule a [Create and Send message](/docs/developer/rest-api/ua/operations/bulk-sending/#createandsend). Unknown identifiers are registered as new channels. This endpoint supports two audience methods: - `create_and_send` array: For smaller audiences, provide email addresses, MSISDNs, or Open channel addresses directly in the request. - `bulk_id`: For larger audiences, upload a CSV using the [Create bulk send audience](/docs/developer/rest-api/ua/operations/bulk-sending/#bulkuploadcreateandsendplatform) endpoint to obtain a `bulk_id`, then reference it in this request. Existing channels that are `opted_in` or have a newer `opted_in` value in the payload receive the message but are not re-registered. You cannot update `opted_in` values for existing channels through this endpoint. Note: This endpoint also accepts Channel IDs for app or web via `bulk_id`, but this works identically to [Schedule message with bulk ID](/docs/developer/rest-api/ua/operations/bulk-sending/#schedulebulksendpush). [Jump to examples ↓](#schedulecreateandsendoperations-examples) ### `POST /api/schedules/create-and-send` {{< warning >}} Duplicate addresses in the `create_and_send` array might receive redundant notifications or fewer notifications than expected. You should remove duplicate addresses from your request before sending a Create and Send message. {{< /warning >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): psh **Request body** The request is much like other Create and Send operations, with a leading `schedule` object. The standard Create and Send payload sits inside a `push` object. **Content-Type:** `application/json` - **`name`** `string` A name for the schedule. - **`push`** `object` **REQUIRED** **One of:** - [Create and Send to email channels]({{< ref "/developer/rest-api/ua/schemas/create-and-send/" >}}#email) The payload for a Create and Send operation to email channels. When sending to email channels, `device_types` must be set to `email`. - [Create and Send to SMS channels]({{< ref "/developer/rest-api/ua/schemas/create-and-send/" >}}#sms) The payload for a Create and Send operation to SMS channels. When sending to SMS channels, `device_types` must be set to `sms`. - [Create and Send MMS notification]({{< ref "/developer/rest-api/ua/schemas/create-and-send/" >}}#mms) The payload for a Create and Send operation that sends a multimedia payload (MMS) to SMS channels. When sending an MMS payload, `device_types` must be set to `mms`. - [Create and Send to open channels]({{< ref "/developer/rest-api/ua/schemas/create-and-send/" >}}#open) The payload for a Create and Send operation to open channels. When sending to open channels, the `device_type` must be set to `open::`. - **`schedule`** `object` **REQUIRED** Similar to other schedule objects. However, Create and Send requests support `scheduled_time` only. **OBJECT PROPERTIES** - **`scheduled_time`** `string` **REQUIRED** The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when you want to perform your Create and Send operation. Users will receive the notification as soon as possible after the specified date-time. Format: `date-time` **Responses** **`202`** Because this operation sends messages, a successful response is nearly identical to a `/api/push` response. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`content_urls`** `array[string]` An array of URLs where the push payload contains a landing page action. Min items: 0, Max items: 100 - **`localized_ids`** `array[string]` An array of identifiers used for reporting. Each ID represents a localized message (push object with `localizations` array). - **`message_ids`** `array[string]` An array of message IDs, each uniquely identifying a Message Center message. - **`ok`** `boolean` Success. - **`operation_id`** `string` A unique string identifying the operation, useful for reporting and troubleshooting. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`push_ids`** `array[string]` An array of push IDs, each uniquely identifying a push. Min items: 1, Max items: 100 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`413`** Returned when the request is too large to be processed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example scheduled Create and Send message* ```http POST /api/schedules/create-and-send HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "schedule": { "scheduled_time" : "2020-11-11T12:00:00" }, "name" : "scheduled winter sale email", "push" : { "audience": { "create_and_send" : [ { "ua_address": "new@example.com", "ua_commercial_opted_in": "2020-11-29T10:34:22" }, { "ua_address" : "ben@example.com", "ua_commercial_opted_in": "2020-11-29T12:45:10" } ] }, "device_types" : [ "email" ], "notification" : { "email": { "subject": "Welcome to the Winter Sale! ", "html_body": "

Seasons Greetings

Check out our winter deals!

Unsubscribe

", "plaintext_body": "Greetings! Check out our latest winter deals! [[ua-unsubscribe href=\"http://unsubscribe.urbanairship.com/email/success.html\"]]", "message_type": "commercial", "sender_name": "Airship", "sender_address": "team@airship.com", "reply_to": "no-reply@airship.com" } }, "campaigns": { "categories": ["winter sale", "west coast"] } } } ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "67c65146-c27f-431f-b54a-83aca694fdd3", "push_ids": [ "8cf8b2a5-7655-40c2-a500-ff498e60453e" ], "schedule_urls": [ "http://go.urbanairship/api/schedules/2d69320c-3c91-5241-fac4-248269eed109" ], "schedules": [ { "push": { "audience": { "create_and_send": [ { "ua_address": "new@example.com", "ua_commercial_opted_in": "2020-11-29T10:34:22" }, { "ua_address": "ben@example.com", "ua_commercial_opted_in": "2020-11-29T12:45:10" } ] }, "device_types": [ "email" ], "notification": { "campaigns": { "categories": [ "winter sale", "west coast" ] }, "email": { "html_body": "

Seasons Greetings

Check out our winter deals!

Unsubscribe

", "message_type": "commercial", "plaintext_body": "Greetings! Check out our latest winter deals! [[ua-unsubscribe href=\"http://unsubscribe.urbanairship.com/email/success.html\"]]", "reply_to": "no-reply@airship.com", "sender_address": "team@airship.com", "sender_name": "Airship", "subject": "Welcome to the Winter Sale! " } } }, "schedule": { "scheduled_time": "2020-11-11T12:00:00" }, "url": "http://go.urbanairship/api/schedules/2d69320c-3c91-5241-fac4-248269eed109" } ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); String htmlBodyString = "

Seasons Greetings

Check out our winter deals!

Unsubscribe

"; String plaintextBodyString = "Greetings! Check out our latest winter deals! [[ua-unsubscribe href=\"http://unsubscribe.urbanairship.com/email/success.html\"]]"; EmailChannel newChannel = EmailChannel.newBuilder() .setAddress("new@example.com") .setCommertialOptedIn(DateTime.parse("2020-11-29T10:34:22Z")) .build(); EmailChannel benChannel = EmailChannel.newBuilder() .setAddress("ben@example.com") .setTransactionalOptedIn(DateTime.parse("2020-11-29T12:45:10Z")) .build(); CreateAndSendAudience audience = new CreateAndSendAudience(EmailChannels.newBuilder() .addChannel(newChannel) .addChannel(benChannel) .build()); CreateAndSendEmailPayload createAndSendEmailPayload = CreateAndSendEmailPayload.newBuilder() .setSubject("Welcome to the Winter Sale! ") .setHtmlBody(htmlBodyString) .setPlaintextBody(plaintextBodyString) .setMessageType(MessageType.TRANSACTIONAL) .setSenderName("Airship") .setSenderAddress("team@airship.com") .setReplyTo("no-reply@airship.com") .build(); Notification notification = Notification.newBuilder() .addDeviceTypeOverride(DeviceType.EMAIL, createAndSendEmailPayload) .build(); Campaigns campaign = Campaigns.newBuilder() .addCategory("winter sale") .addCategory("west coast") .build(); CreateAndSendPayload payload = CreateAndSendPayload.newBuilder() .setAudience(audience) .setNotification(notification) .setCampaigns(campaign) .build(); CreateAndSendSchedulePayload schedulePayload = CreateAndSendSchedulePayload.newBuilder() .setPayload(payload) .setScheduleTime(DateTime.parse("2020-11-11T12:00:00")) .setName("scheduled winter sale email") .build(); CreateAndSendScheduleRequest scheduleRequest = CreateAndSendScheduleRequest.newRequest(schedulePayload) Response response = client.execute(scheduleRequest); ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') email_notification = UA::EmailNotification.new(client: airship) email_notification.bypass_opt_in_level = false email_notification.html_body = "

Seasons Greetings

Check out our winter deals!

Unsubscribe

" email_notification.message_type = 'transactional' email_notification.plaintext_body = 'Greetings! Check out our latest winter deals! [[ua-unsubscribe href=\"http://unsubscribe.urbanairship.com/email/success.html\"]]' email_notification.reply_to = 'no-reply@airship.com' email_notification.sender_address = 'team@airship.com' email_notification.sender_name = 'Airship' email_notification.subject = 'Welcome to the Winter Sale!' override = email_notification.email_override send_it = UA::CreateAndSend.new(client: airship) send_it.addresses = [ { "ua_address": "new@example.com", "ua_commercial_opted_in": "2020-10-28T10:34:22" } ] send_it.device_types = [ "email" ] send_it.campaigns = ["winter sale", "west coast"] send_it.notification = email_notification.email_override send_it.name = "scheduled winter sale email" send_it.scheduled_time = "2020-12-08T11:06:00" send_it.schedule ``` *Example scheduled Create and Send with bulk ID* ```http POST /api/schedules/create-and-send HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "schedule": { "scheduled_time": "2020-11-11T12:00:00" }, "name": "scheduled winter sale email", "push": { "audience": { "bulk_id": "26425d51-fbab-4ad8-bd5f-9560ee84b087" }, "device_types": [ "email" ], "notification": { "email": { "subject": "Welcome to the Winter Sale!", "html_body": "

Seasons Greetings {{name}}

Check out our winter deals!

Unsubscribe

", "plaintext_body": "Greetings {{name}}! Check out our latest winter deals! [[ua-unsubscribe href=\"http://unsubscribe.urbanairship.com/email/success.html\"]]", "message_type": "commercial", "sender_name": "Airship", "sender_address": "team@airship.com", "reply_to": "no-reply@airship.com" } }, "campaigns": { "categories": ["winter sale", "west coast"] } } } ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "67c65146-c27f-431f-b54a-83aca694fdd3", "schedule_urls": [ "http://go.urbanairship/api/schedules/2d69320c-3c91-5241-fac4-248269eed109" ] } ``` --- ## Schedule message with bulk ID {#schedulebulksendpush} Schedule a message to existing channels using a `bulk_id`. Inactive channels are dropped. Before calling this endpoint, obtain a `bulk_id` from the [Create bulk send audience](/docs/developer/rest-api/ua/operations/bulk-sending/#bulkuploadcreateandsendplatform) endpoint. [Jump to examples ↓](#schedulebulksendpush-examples) ### `POST /api/schedules/bulk-send` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): psh **Request body** A Send a message with bulk ID payload. **Content-Type:** `application/json` [Scheduled bulk send object]({{< ref "/developer/rest-api/ua/schemas/bulk-sending/" >}}#scheduledbulksendobject) **Responses** **`202`** The push notification has been accepted for processing. The response contains `push_id`, `message_id`, and/or `content_url` arrays based on the type of push. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`content_urls`** `array[string]` An array of URLs where the push payload contains a landing page action. Min items: 0, Max items: 100 - **`localized_ids`** `array[string]` An array of identifiers used for reporting. Each ID represents a localized message (push object with `localizations` array). - **`message_ids`** `array[string]` An array of message IDs, each uniquely identifying a Message Center message. - **`ok`** `boolean` Success. - **`operation_id`** `string` A unique string identifying the operation, useful for reporting and troubleshooting. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`push_ids`** `array[string]` An array of push IDs, each uniquely identifying a push. Min items: 1, Max items: 100 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`413`** Returned when the request is too large to be processed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`429`** Too many requests hit the API too quickly. For example, if we are not ready to create a channel for this payload; e.g., it is rate limited. You should wait before retrying the channel creation. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example schedule message with bulk ID* ```http POST /api/schedules/bulk-send HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3; Content-type: application/json { "schedule": { "scheduled_time" : "2024-11-07T12:00:00" }, "name" : "scheduled bulk send", "push" : { "audience" : { "bulk_id" : "36d5a261-0454-40f5-b952-942c4b2b0f22" }, "device_types" : [ "android" ], "notification" : { "alert" : "Hope you voted" }, "campaigns": { "categories": ["midterms2024", "getoutthevote2024"] } } } ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "67c65146-c27f-431f-b54a-83aca694fdd3", "schedule_urls": [ "http://go.urbanairship/api/schedules/2d69320c-3c91-5241-fac4-248269eed109" ], "schedules": [ { "url": "http://go.urbanairship/api/schedules/2d69320c-3c91-5241-fac4-248269eed109" "schedule": { "scheduled_time" : "2024-11-07T12:00:00" } "push": { "audience": { "bulk_id" : "36d5a261-0454-40f5-b952-942c4b2b0f22" }, "device_types" : [ "open::rcs" ], "notification" : { "alert" : "Welcome to the winter sale!!" }, "campaigns": { "categories": ["winter sale", "west coast"] } } } ], "push_ids": ["8cf8b2a5-7655-40c2-a500-ff498e60453e"] } ``` --- ## Send message with bulk ID {#bulksendpush} Send an immediate message to existing channels using a `bulk_id`. Inactive channels are dropped. Before calling this endpoint, obtain a `bulk_id` from the [Create bulk send audience](/docs/developer/rest-api/ua/operations/bulk-sending/#bulkuploadcreateandsendplatform) endpoint. [Jump to examples ↓](#bulksendpush-examples) ### `POST /api/bulk-send` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): psh **Request body** A Send a message with bulk ID payload. **Content-Type:** `application/json` [Bulk send object]({{< ref "/developer/rest-api/ua/schemas/bulk-sending/" >}}#bulksendobject) **Responses** **`202`** The push notification has been accepted for processing. The response contains `push_id`, `message_id`, and/or `content_url` arrays based on the type of push. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`content_urls`** `array[string]` An array of URLs where the push payload contains a landing page action. Min items: 0, Max items: 100 - **`localized_ids`** `array[string]` An array of identifiers used for reporting. Each ID represents a localized message (push object with `localizations` array). - **`message_ids`** `array[string]` An array of message IDs, each uniquely identifying a Message Center message. - **`ok`** `boolean` Success. - **`operation_id`** `string` A unique string identifying the operation, useful for reporting and troubleshooting. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`push_ids`** `array[string]` An array of push IDs, each uniquely identifying a push. Min items: 1, Max items: 100 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`413`** Returned when the request is too large to be processed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`429`** Too many requests hit the API too quickly. For example, if we are not ready to create a channel for this payload; e.g., it is rate limited. You should wait before retrying the channel creation. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example send message with bulk ID* ```http POST /api/bulk-send HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3; Content-type: application/json { "audience" : { "bulk_id" : "36d5a261-0454-40f5-b952-942c4b2b0f22" }, "device_types" : [ "android" ], "notification" : { "alert" : "Welcome to the winter sale!!" }, "campaigns": { "categories": ["winter sale", "west coast"] } } ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "67c65146-c27f-431f-b54a-83aca694fdd3", "push_ids": [ "c0eead17-333b-4f86-8a42-9fb7be1ed627" ], "message_ids": [], "content_urls": [] } ``` --- ## Validate Create and Send payload {#validatecreateandsendpayload} Validate a [Create and Send](/docs/developer/rest-api/ua/operations/bulk-sending/#createandsend) payload without creating channels or sending messages. It only parses and validates your payload. [Jump to examples ↓](#validatecreateandsendpayload-examples) ### `POST /api/create-and-send/validate` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): psh **Request body** **Content-Type:** `application/json` **One of:** - [Create and Send to email channels]({{< ref "/developer/rest-api/ua/schemas/create-and-send/" >}}#email) The payload for a Create and Send operation to email channels. When sending to email channels, `device_types` must be set to `email`. - [Create and Send to SMS channels]({{< ref "/developer/rest-api/ua/schemas/create-and-send/" >}}#sms) The payload for a Create and Send operation to SMS channels. When sending to SMS channels, `device_types` must be set to `sms`. - [Create and Send MMS notification]({{< ref "/developer/rest-api/ua/schemas/create-and-send/" >}}#mms) The payload for a Create and Send operation that sends a multimedia payload (MMS) to SMS channels. When sending an MMS payload, `device_types` must be set to `mms`. - [Create and Send to open channels]({{< ref "/developer/rest-api/ua/schemas/create-and-send/" >}}#open) The payload for a Create and Send operation to open channels. When sending to open channels, the `device_type` must be set to `open::`. **Responses** **`200`** The payload was valid. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`413`** Returned when the request is too large to be processed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example Validate Create and Send payload* ```http POST /api/create-and-send/validate HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "create_and_send" : [ { "ua_address": "new@example.com", "ua_commercial_opted_in": "2020-11-29T10:34:22" }, { "ua_address" : "ben@example.com", "ua_commercial_opted_in": "2020-11-29T12:45:10" } ] }, "device_types" : [ "email" ], "notification" : { "email": { "subject": "Welcome to the Winter Sale! ", "html_body": "

Seasons Greetings

Check out our winter deals!

Unsubscribe

", "plaintext_body": "Greetings! Check out our latest winter deals! [[ua-unsubscribe href=\"http://unsubscribe.urbanairship.com/email/success.html\"]]", "message_type": "commercial", "sender_name": "Airship", "sender_address": "team@airship.com", "reply_to": "no-reply@airship.com" } }, "campaigns": { "categories": ["winter sale", "west coast"] } } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); String htmlBodyString = "

Seasons Greetings

Check out our winter deals!

Unsubscribe

"; String plaintextBodyString = "Greetings! Check out our latest winter deals! [[ua-unsubscribe href=\"http://unsubscribe.urbanairship.com/email/success.html\"]]"; EmailChannel newChannel = EmailChannel.newBuilder() .setAddress("new@example.com") .setCommertialOptedIn(DateTime.parse("2020-11-29T10:34:22Z")) .build(); EmailChannel benChannel = EmailChannel.newBuilder() .setAddress("ben@example.com") .setTransactionalOptedIn(DateTime.parse("2020-11-29T12:45:10Z")) .build(); CreateAndSendAudience audience = new CreateAndSendAudience(EmailChannels.newBuilder() .addChannel(newChannel) .addChannel(benChannel) .build()); CreateAndSendEmailPayload createAndSendEmailPayload = CreateAndSendEmailPayload.newBuilder() .setSubject("Welcome to the Winter Sale! ") .setHtmlBody(htmlBodyString) .setPlaintextBody(plaintextBodyString) .setMessageType(MessageType.TRANSACTIONAL) .setSenderName("Airship") .setSenderAddress("team@airship.com") .setReplyTo("no-reply@airship.com") .build(); Notification notification = Notification.newBuilder() .addDeviceTypeOverride(DeviceType.EMAIL, createAndSendEmailPayload) .build(); Campaigns campaign = Campaigns.newBuilder() .addCategory("winter sale") .addCategory("west coast") .build(); CreateAndSendPayload payload = CreateAndSendPayload.newBuilder() .setAudience(audience) .setNotification(notification) .setCampaigns(campaign) .build(); CreateAndSendRequest request = CreateAndSendRequest.newRequest(payload) .setValidateOnly(true); Response response = client.execute(request); ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') email_notification = UA::EmailNotification.new(client: airship) email_notification.bypass_opt_in_level = false email_notification.html_body = "

Seasons Greetings

Check out our winter deals!

Unsubscribe

" email_notification.message_type = 'transactional' email_notification.plaintext_body = 'Greetings! Check out our latest winter deals! [[ua-unsubscribe href=\"http://unsubscribe.urbanairship.com/email/success.html\"]]' email_notification.reply_to = 'no-reply@airship.com' email_notification.sender_address = 'team@airship.com' email_notification.sender_name = 'Airship' email_notification.subject = 'Welcome to the Winter Sale!' override = email_notification.email_override send_it = UA::CreateAndSend.new(client: airship) send_it.addresses = [ { "ua_address": "new@example.com", "ua_commercial_opted_in": "2020-11-29T10:34:22" } ] send_it.device_types = [ "email" ] send_it.campaigns = ["winter sale", "west coast"] send_it.notification = email_notification.email_override send_it.validate ``` --- ## Validate message with bulk ID {#validatebulksendpush} Accept the same range of payloads as POSTing to [`/api/bulk-send`](/docs/developer/rest-api/ua/operations/bulk-sending/#bulksendpush), but parse and validate only, without sending any messages. Before calling this endpoint, obtain a `bulk_id` using the [Create bulk send audience](/docs/developer/rest-api/ua/operations/bulk-sending/#bulkuploadcreateandsendplatform) operation. [Jump to examples ↓](#validatebulksendpush-examples) ### `POST /api/bulk-send/validate` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): psh **Request body** A single bulk send object. **Content-Type:** `application/json` [Bulk send object]({{< ref "/developer/rest-api/ua/schemas/bulk-sending/" >}}#bulksendobject) **Responses** **`200`** The payload was valid. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`413`** Returned when the request is too large to be processed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example validate message with bulk ID* ```http POST /api/bulk-send/validate HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3; Content-type: application/json { "audience" : { "bulk_id" : "36d5a261-0454-40f5-b952-942c4b2b0f22" }, "device_types" : [ "android" ], "notification" : { "alert" : "Welcome to the winter sale!!" }, "campaigns": { "categories": ["winter sale", "west coast"] } } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` --- # Channels > Channels are Airship's unique identifiers for addressing applications on iOS, Android, Fire OS, and web devices. ## Channel listing {#getchannels} List all channels registered to this app key, along with associated data and metadata. [Jump to examples ↓](#getchannels-examples) ### `GET /api/channels` {{< note >}} Tags added to a channel via the [Named Users tag endpoint](/docs/developer/rest-api/ua/operations/tags/#modifynamedusertags) will not appear with a request to this endpoint. To view those tags, you must [look up the Named User](/docs/developer/rest-api/ua/operations/named-users/#getnameduser) associated with the channel. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `limit` | `integer` | | The default limit is 1,000 channel objects returned per request. Set the limit to 1,000 or fewer in your API calls. Max: 1000 | **Responses** **`200`** Returns OK for success with the JSON response. Tags added to a channel using `/named_users/tags` are not returned from this endpoint. To view those tags, you must look up the Named User associated with the channel. Response headers: | Name | Type | Description | |------|------|-------------| | `Link` | `string` | Provides the URL to the current page of results. The query within the URL contains the `limit` (the number of results on the page) and `start` (the first `channel_id` in the result set) parameters. | Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`channels`** `array` <[Channel listing object]({{< ref "/developer/rest-api/ua/schemas/channels/" >}}#channellistingobject)> An array of channel objects. - **`next_page`** `string` If there is more than one page of results, use this link to get the next page of results. Format: `url` Example: `https://go.urbanairship.com/api/channels?limit=1000&start=535ec31e-4b07-4b26-bead-a1c0e94e133c` - **`ok`** `boolean` Success. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/channels HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 Data-Attribute: channels Link: ; rel=next { "ok": true, "next_page": "https://go.urbanairship.com/api/channels?start=07AAFE44CD82C2F4E3FBAB8962A95B95F90A54857FB8532A155DE3510B481C13&limit=2", "channels": [ { "channel_id": "9c36e8c7-5a73-47c0-9716-99fd3d4197d5", "device_type": "android", "push_address": "FE66489F304DC75B8D6E8200DFF8A456E8DAEACEC428B427E9518741C92C6660", "opt_in": true, "installed": true, "background": true, "created": "2020-03-06T18:52:59", "last_registration": "2020-10-07T21:28:35", "named_user_id": "some_id_that_maps_to_your_systems", "alias": "null", "tags": [ "tag1", "tag2" ], "tag_groups": { "tag_group_1": ["tag1", "tag2"], "tag_group_2": ["tag1", "tag2"] }, "device_attributes": { "ua_device_os": "10", "ua_country": "US", "ua_device_model": "SM-G973U", "ua_local_tz": "America/Los_Angeles", "ua_app_version": "2020-02-01T002322-goat", "ua_location_settings": "true", "ua_language": "en", "ua_sdk_version": "12.2.0", "ua_carrier": "Verizon " }, "attributes": { "first_name": "Cool", "last_name": "Person", "birthdate": "1983-03-15T00:00:00", } }, { "channel_id": "bd36e8c7-5a73-47c0-9716-99fd3d4197d5", "device_type": "ios", "push_address": null, "opt_in": false, "installed": true, "background": true, "created": "2020-03-06T18:52:59", "last_registration": "2020-10-07T21:28:35", "named_user_id": "some_id_that_maps_to_your_systems", "alias": "null", "tags": [ "tag1", "tag2" ], "tag_groups": { "tag_group_1": ["tag1", "tag2"], "tag_group_2": ["tag1", "tag2"] }, "ios": { "badge": 0, "quiettime": { "start": null, "end": null }, "tz": null } } ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); ChannelRequest request = ChannelRequest.newRequest(); Response response = client.execute(request); ChannelView channels = response.getBody().get().getChannelView().get(); ``` ```python from urbanairship import ( BasicAuthClient, ChannelList ) client = BasicAuthClient( key='', secret='' ) channel_id = None for channel in ChannelList(client): channel_id = channel.channel_id print(channel.channel_id, channel.device_type, channel.tags, channel.push_address, channel.named_user_id, channel.opt_in) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') channel_list = UA::ChannelList.new(client: airship) channel_list.each do |channel| puts(channel) end puts(channel_list.count) ``` --- ## Channel lookup {#getchannel} Fetch an individual channel registered to the app key, along with associated data and metadata. [Jump to examples ↓](#getchannel-examples) ### `GET /api/channels/{channel_id}` {{< note >}} Tags added to a channel via the [Named Users tag endpoint](/docs/developer/rest-api/ua/operations/tags/#modifynamedusertags) will not appear with a request to this endpoint. To view those tags, you must [look up the Named User](/docs/developer/rest-api/ua/operations/named-users/#getnameduser) associated with the channel. {{< /note >}} **Security:** - [basicAppAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAppAuth) - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `channel_id` | `string` | Required | The unique channel identifier. | **Responses** **`200`** Tags added to a channel using `/named_users/tags` are not returned from this endpoint. To view those tags, you must look up the Named User associated with the channel. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`channel`** `object` A channel object. **One of:** - [Channel listing object]({{< ref "/developer/rest-api/ua/schemas/channels/" >}}#channellistingobject) Describes a channel listing object. - **Open channel object** `object` Describes an open channel. - **`address`** `string` The address to send push notifications to when `device_type` is `email` or `open`. Example: `email@example.com` - **`channel_id`** `string` The unique channel identifier for a device. Format: `uuid` Example: `9c36e8c7-5a73-47c0-9716-99fd3d4197d5` - **`created`** `string` The creation [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) of this channel. Format: `date-time` Read only: true - **`last_registration`** `string` The last registration [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) of this channel, if known. Format: `date-time` Nullable: true Read only: true - **`locale_country`** `string` The two-letter country locale short code. Will set the `ua_locale_country` tag group to the specified value. - **`locale_language`** `string` The two-letter language locale short code. Will set the `ua_locale_language` tag group to the specified value. - **`named_user_id`** `string` A customer-chosen ID that represents the device user, e.g., CRM ID. This ID cannot have leading or trailing whitespace. Min length: 1, Max length: 128 Example: `john_doe` Nullable: true - **`open`** `object` Contains options that apply when the `device_type` is set to `open`. **OBJECT PROPERTIES** - **`identifiers`** `object` A set of up to 100 key:value pairs representing identifiers for this channel in your own delivery systems and delivered as a part of webhook payloads. Example: `[object Object]` - **`old_address`** `string` If a channel exists for the value of `old_address`, replaces that channel's address with the value of `address`. Use infrequently, such as when an end user's phone number or email address permanently changes. - **`open_platform_name`** `string` The name of the open channel that this `channel_id` is registered on. Example: `Slack` - **`opt_in`** `boolean` If true, the channel is opted in to push notifications. If false, it is not. - **`set_tags`** `boolean` When `true`, replaces all device tags on the channel with the set provided in `"tags"`. When `false` or absent, the `"tags"` set is unioned with existing device tags. - **`tag_groups`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> One or more tag group objects (including [Device Property Tags](/docs/reference/device-property-tags/)) associated with this channel. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`tags`** `array[string]` An array of tags associated with this channel. Min items: 0, Max items: 1000 Example: `Federer fan,Messi fan` - **`timezone`** `string` An IANA tzdata identifier for the time zone as a string, e.g., `"America/Los_Angeles"`. Will set the `timezone` tag group tag with the specified value. - **`type`** `string` Specifies the device platform for a channel. Possible values: `open` - **`ok`** `boolean` Success. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/channels/9c36e8c7-5a73-47c0-9716-99fd3d4197d5 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 Data-Attribute: channel { "ok": true, "channel": { "channel_id": "9c36e8c7-5a73-47c0-9716-99fd3d4197d5", "device_type": "ios", "installed": true, "opt_in": false, "background": true, "push_address": "FE66489F304DC75B8D6E8200DFF8A456E8DAEACEC428B427E9518741C92C6660", "created": "2020-08-08T20:41:06", "last_registration": "2020-05-01T18:00:27", "named_user_id": "some_id_that_maps_to_your_systems", "alias": null, "tags": [ "tag1", "tag2" ], "tag_groups": { "tag_group_1": ["tag1", "tag2"], "tag_group_2": ["tag1", "tag2"] }, "ios": { "badge": 0, "quiettime": { "start": null, "end": null }, "tz": "America/Los_Angeles" }, "open_tracking_opted_in": "2022-11-26T00:00:00", "open_tracking_opted_out": "2022-12-11T00:00:00", "click_tracking_opted_in": "2022-11-26T00:00:00", "click_tracking_opted_out": "2022-12-11T00:00:00" } } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); ChannelRequest request = ChannelRequest.newRequest("9c36e8c7-5a73-47c0-9716-99fd3d4197d5"); Response response = client.execute(request); ChannelView channel = response.getBody().get().getChannelView().get(); ``` ```python from urbanairship import ( BasicAuthClient, ChannelInfo ) client = BasicAuthClient( key='', secret='' ) channel = ChannelInfo(client).lookup('9c36e8c7-5a73-47c0-9716-99fd3d4197d5') print(channel.channel_id, channel.device_type, channel.tags, channel.push_address, channel.named_user_id, channel.opt_in) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') channel_client = UA::ChannelInfo.new(client: airship) channel_info = channel_client.lookup(uuid: '9c36e8c7-5a73-47c0-9716-99fd3d4197d5') puts(channel_info) ``` *Example open channel lookup response with all optional keys* ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 Data-Attribute: channel { "ok": true, "channel": { "channel_id": "b8f9b663-0a3b-cf45-587a-be880946e881", "type": "open", "opt_in": true, "address": "example@example.com", "created": "2013-08-08T20:41:06", "last_registration": "2014-05-01T18:00:27", "named_user_id": "john_doe_123", "tags": ["asdf"], "tag_groups": { "timezone" : ["America/Los_Angeles"], "locale_country" : ["US"], "locale_language" : ["en"], "tag_group_1" : ["tag1", "tag2"], "tag_group_2" : ["tag1", "tag2"] }, "open" { "open_platform_name": "email", "identifiers": { "com.example.external_id": "df6a6b50-9843-7894-1235-12aed4489489" } } } } ``` *Example open channel lookup response with only required keys* ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 Data-Attribute: channel { "ok": true, "channel": { "channel_id": "b8f9b663-0a3b-cf45-587a-be880946e881", "type": "open", "opt_in": false, "address": "example@example.com", "created": "2013-08-08T20:41:06", "last_modified": "2014-05-01T18:00:27", "tags": [], "tag_groups" {}, "open": { "open_platform_name": "email" } } } ``` --- ## Channel tags {#modifychanneltags} Add, remove, or set tags on a channel. [Jump to examples ↓](#modifychanneltags-examples) ### `POST /api/channels/tags` {{< important >}} A tag must be < 128 characters. A request with one or more tags longer than 128 characters will return a 400 response. We support up to 1,000 tags per channel. Adding more than 1,000 tags per channel can cause latency and service interruptions. We strongly recommend removing unused tags whenever possible, and using Custom Events when appropriate. Please [contact Support](https://support.airship.com/) if you believe your use case requires more than 1,000 tags per channel, and they will help you find an alternative. {{< /important >}} **Security:** - [basicAppAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAppAuth) - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** **Content-Type:** `application/json` - **`add`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Adds the specified tags to the channel. Tags that are already present are not modified/removed as a result of this operation. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`audience`** `object` **REQUIRED** Specifies one or more channels that you want to apply tag operations to. **OBJECT PROPERTIES** - **`amazon_channel`** `array[string]` The unique channel identifier for a Fire OS device. Min items: 1, Max items: 1000 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` - **`android_channel`** `array[string]` The unique channel identifier for an Android device. Min items: 1, Max items: 1000 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` - **`channel`** `array[string]` The unique channel identifier for `email`, `sms`, `open`, or `web` device types. Min items: 1, Max items: 1000 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` - **`ios_channel`** `array[string]` The unique channel identifier for an iOS device. Min items: 1, Max items: 1000 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` - **`remove`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Removes the specified tags from the channel. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`set`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Assigns a list of tags exactly. Any previously set tags that are not in this current list will be removed. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. **Responses** **`200`** Returns OK for success. If a tag request is partially valid, i.e., at least one tag group exists and is active, a 200 is returned with a warning in the response about the tag groups that failed to update. The tag groups listed in the warning will be CSV-formatted. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` If true, your request was processed normally. - **`warnings`** `array[string]` Returned when some tag groups could not be updated. Contains a string indicating each tag group that could not be updated and the reason the update failed. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/tags HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "ios_channel": "b8f9b663-0a3b-cf45-587a-be880946e881", "android_channel": "13863b3c-f860-4bbf-a9f1-4d785379b8a2" }, "add": { "my_fav_tag_group1": ["tag1", "tag2", "tag3"], "my_fav_tag_group2": ["tag1", "tag2", "tag3"], "my_fav_tag_group3": ["tag1", "tag2", "tag3"] } } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "warnings": ["The following tag groups do not exist: my_fav_tag_group2", "The following tag groups are deactivated: my_fav_tag_group3"] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); ChannelTagRequest request = ChannelTagRequest.newRequest() .addIOSChannel("b8f9b663-0a3b-cf45-587a-be880946e881") .addAndroidChannel("13863b3c-f860-4bbf-a9f1-4d785379b8a2") .addTags("my_fav_tag_group1", ImmutableSet.of("tag1", "tag2", "tag3")) .addTags("my_fav_tag_group2", ImmutableSet.of("tag1", "tag2", "tag3")) .addTags("my_fav_tag_group3", ImmutableSet.of("tag1", "tag2", "tag3")); Response response = client.execute(request); ``` ```python import urbanairship as ua client = ua.BasicAuthClient('', '') channel_tags = ua.devices.ChannelTags(client) ios_audience = ['b8f9b663-0a3b-cf45-587a-be880946e881'] android_audience = ['13863b3c-f860-4bbf-a9f1-4d785379b8a2'] channel_tags.set_audience(ios_audience, android_audience ) channel_tags.add('my_fav_tag_group1', ['tag1', 'tag2', 'tag3']) channel_tags.remove('my_fav_tag_group2', 'tag4') channel_tags.send() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') channel_tags = UA::ChannelTags.new(client: airship) ios_audience = 'b8f9b663-0a3b-cf45-587a-be880946e881' android_audience = '13863b3c-f860-4bbf-a9f1-4d785379b8a2' channel_tags.set_audience( ios: ios_audience, android: android_audience ) channel_tags.add(group_name: 'my_fav_tag_group1', tags: ['tag1', 'tag2', 'tag3']) channel_tags.remove(group_name: 'my_fav_tag_group2', tags: 'tag4') channel_tags.send_request ``` --- ## Set or remove attributes on channels {#modifychannelattributes} Set or remove attributes on a channel. Aside from Airship's [default attributes](/docs/reference/data-collection/attributes/#default-attributes), you must [define attributes in the Airship dashboard](/docs/guides/audience/attributes/adding/) before you can set them on channels. [Jump to examples ↓](#modifychannelattributes-examples) ### `POST /api/channels/attributes` {{< important >}} Use the [Named Users endpoint](/docs/developer/rest-api/ua/operations/named-users/#modifynameduserattributes) to set or remove attributes on Named Users. {{< /important >}} **Security:** - [basicAppAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAppAuth) - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** **Content-Type:** `application/json` - **`attributes`** `object` <[Attribute assignment]({{< ref "/developer/rest-api/ua/schemas/attributes/" >}}#attributesobject)> **REQUIRED** - **`audience`** `object` **REQUIRED** The channel(s) you want to set or remove attributes for. **OBJECT PROPERTIES** - **`amazon_channel`** `object` The unique channel identifier used to target a Fire OS device. **OBJECT PROPERTIES** - **`amazon_channel`** `object` **REQUIRED** **One of:** - `string` - `array` - **`android_channel`** `object` The unique channel identifier used to target an Android device. **OBJECT PROPERTIES** - **`android_channel`** `object` **REQUIRED** **One of:** - `string` - `array` - **`channel`** `object` The unique channel identifier used to target an open channel device or web device, i.e., web browser. **OBJECT PROPERTIES** - **`channel`** `object` **REQUIRED** **One of:** - `string` - `array` - **`email_address`** `array[string]` The unique channel identifier used to target an email address. Min items: 1, Max items: 100 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` - **`ios_channel`** `object` The unique channel identifier used to target an iOS device. **OBJECT PROPERTIES** - **`ios_channel`** `object` **REQUIRED** **One of:** - `string` - `array` - **`sms_id`** `object` Selects a single SMS device. The `msisdn` must be `opted_in` to receive notifications. **OBJECT PROPERTIES** - **`msisdn`** `string` **REQUIRED** The recipient phone number. Min length: 1, Max length: 128 - **`sender`** `string` **REQUIRED** The sender that the app is configured to send SMS messages from. Min length: 1, Max length: 128 - **`web_channel`** `array[string]` The unique channel identifier used to target a web device. Min items: 1, Max items: 100 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` **Responses** **`200`** The operation was successful. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` If true, your request was successful. - **`warning`** `string` Alerts you if your request could not be processed. You may receive a 200 with a warning if you provide a `value` that does not match your attribute type. For example, an attribute that expects a numeric value will allow a value of "25" but fail if you input "twenty-five". **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/attributes HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "android_channel": ["13863b3c-f860-4bbf-a9f1-4d785379b8a2"] }, "attributes": [ { "action": "set", "key": "major_league", "value": "sf_giants" }, { "action": "remove", "key": "minor_league" }, { "action": "set", "key": "position", "value": "LF" }, { "action": "set", "key": "specialData", "value": { "timestamp": "1983-03-15 10:00:00", "specialties": [ { "specialty": { "name": "golden", "property": "small" } }, { "specialty": { "name": "silver", "property": "medium" } } ] } } ] } ``` ```python from urbanairship import ( BasicAuthClient, Attribute ) import json client = BasicAuthClient( key='', secret='' ) set_major_league = Attribute( action="set", key="major_league", value="sf_giants" ) remove_minor_league = Attribute( action="remove", key="minor_league" ) set_position = Attribute( action="set", key="position", value="LF" ) specialties_string = "{" + \ " \"timestamp\": \"1983-03-15 10:00:00\"," + \ " \"specialties\": [{" + \ " \"specialty\": {" + \ " \"name\": \"golden\"," + \ " \"property\": \"small\"" + \ " }" + \ " }," + \ " {" + \ " \"specialty\": {" + \ " \"name\": \"silver\"," + \ " \"property\": \"medium\"" + \ " }" + \ " }" + \ " ]" + \ "}" specialties_json = json.loads(specialties_string) specialties = Attribute( action="set", key="specialties", value=specialties_json ) modifications = Attribute.ModifyAttributes( client=client, attributes=[set_major_league, remove_minor_league, set_position], channel="13863b3c-f860-4bbf-a9f1-4d785379b8a2" ) modifications.send() ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); Attribute setMajorLeague = Attribute.newBuilder() .setAction(AttributeAction.SET) .setKey("major_league") .setValue("sf_giants") .build(); Attribute removeMinorLeague = Attribute.newBuilder() .setAction(AttributeAction.REMOVE) .setKey("minor_league") .build(); Attribute setPosition = Attribute.newBuilder() .setAction(AttributeAction.SET) .setKey("position") .setValue("LF") .build(); String specialtiesStr = "{" + " \"timestamp\": \"1983-03-15 10:00:00\"," + " \"specialties\": [{" + " \"specialty\": {" + " \"name\": \"golden\"," + " \"property\": \"small\"" + " }" + " }," + " {" + " \"specialty\": {" + " \"name\": \"silver\"," + " \"property\": \"medium\"" + " }" + " }" + " ]" + "}"; JSONObject specialtiesJson = new JSONObject(specialtiesStr); Attribute setSpecialties = Attribute.newBuilder() .setAction(AttributeAction.SET) .setKey("specialties") .setValue(specialtiesJson) .build(); ChannelAttributesPayload payload = ChannelAttributesPayload.newBuilder() .addAttribute(setMajorLeague) .addAttribute(removeMinorLeague) .addAttribute(setPosition) .setAudience(AttributeAudience.newBuilder() .addDeviceId(AttributeAudienceType.ANDROID_CHANNEL, "13863b3c-f860-4bbf-a9f1-4d785379b8a2") .build()) .build(); ChannelAttributesRequest request = ChannelAttributesRequest.newRequest(payload); Response response = client.execute(request); ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') channel_info = UA::ChannelInfo.new(client: airship) channel_info.audience = {"android_channel": '13863b3c-f860-4bbf-a9f1-4d785379b8a2'} channel_info.attributes = { "action": "set", "key": "major_league", "value": "sf_giants" } channel_info.set_attributes ``` *Example request with dates and numbers* ```http POST /api/channels/attributes HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "android_channel": ["13863b3c-f860-4bbf-a9f1-4d785379b8a2"] }, "attributes": [ { "action": "set", "key": "birthday", "value": "1983-03-15 10:00:00" }, { "action": "set", "key": "fav_number", "value": 42 }, { "action": "remove", "key": "another_attribute" } ] } ``` --- ## Subscribe or unsubscribe channels to/from subscription lists {#modifychannelsubscriptions} Subscribe or unsubscribe channels to/from Subscription Lists. [Jump to examples ↓](#modifychannelsubscriptions-examples) ### `POST /api/channels/subscription_lists` {{< note >}} If you are using a single-channel Preference Center created before October 10, 2022, that has not been [migrated to user-level](/docs/guides/messaging/features/preference-centers/#migrating-to-a-user-level-preference-center), use the [`/api/channels/subscription_lists` endpoint](/docs/developer/rest-api/ua/operations/channels/#modifychannelsubscriptions) to add or remove individual channels to/from your subscription list. Otherwise, use the [Scoped Named User batch operations endpoint](/docs/developer/rest-api/ua/operations/named-users/#performnameduserscopedbatchoperations) to do so. {{< /note >}} {{< important >}} You must first [create a subscription list in the dashboard](/docs/guides/audience/segmentation/audience-lists/subscription/#creating-a-list), then you can refer to its ID when subscribing users. When subscribing users, if the list has not already been created in the dashboard, then the list will be created at the same time but will not be accessible from the dashboard; the list will available for API use only. {{< /important >}} **Security:** - [basicAppAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAppAuth) - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** **Content-Type:** `application/json` **All of:** - [Audience selector (max 100)]({{< ref "/developer/rest-api/ua/schemas/audience-selection/" >}}#audienceselector100) An audience selector forms the expression that determines the set of channels to target. - `array` An array of Subscription List objects. **Responses** **`202`** Returns OK for success. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/subscription_lists HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "subscription_lists": [ { "action":"subscribe", "list_id":"intriguing_ideas" }, { "action":"unsubscribe", "list_id":"animal_facts" } ], "audience": { "ios_channel": [ "b8f9b663-0a3b-cf45-587a-be880946e881" ], "email_address": [ "homer@example.com", "nick@example.com" ] } } ``` ```python import urbanairship as ua client = ua.BasicAuthClient('', '') subscription_list = ua.SubscriptionList(client) subscription_list.subscribe(list_id="intriguing_ideas", audience=ua.email("nick@example.com") ) subscription_list.unsubscribe(list_id="animal_facts", audience=ua.ios_channel( "b8f9b663-0a3b-cf45-587a-be880946e881" ) ) ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); SubscriptionList subscriptionList = SubscriptionList.newBuilder() .setListId("big_deals") .setAction(SubscriptionListAction.SUBSCRIBE) .build(); SubscriptionListPayload payload = SubscriptionListPayload.newBuilder() .addSubscriptionList(subscriptionList) .setAudience(ChannelAudience.newBuilder() .addDeviceId(ChannelAudienceType.ANDROID_CHANNEL, "002b4104-c94f-418d-be86-ead3214b3244").build()) .build(); SubscriptionListRequest request = SubscriptionListRequest.newRequest(payload); Response response = client.execute(request); ``` --- ## Uninstall channels {#uninstallchannels} Uninstalls a channel, removing it and all accompanying analytic data (including Performance Analytics) from Airship systems in accordance with data privacy law compliance. Uninstallation is handled automatically by the Airship SDK and push systems. If a user decides to opt in to communications again (either by using your app or other user preferences), they will create a new channel and a new set of analytic data. The value of a Channel ID may be the same as before however none of the associated metadata will persist when a user opts in again. A new Channel ID will be created if the user clears their browser’s cookies and data, deletes and reinstalls the app, etc. See [Individual Data Privacy Rights Under Data Privacy Laws](/docs/guides/audience/privacy/individual-data-privacy/) for more information about data privacy law compliance. [Jump to examples ↓](#uninstallchannels-examples) ### `POST /api/channels/uninstall` {{< note >}} Channel uninstallation, like channel creation, is an asynchronous operation and may take some time to complete. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** **Content-Type:** `application/json` Type: `array` **Responses** **`202`** Returns OK for success. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/uninstall HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json [ { "channel_id": "b8f9b663-0a3b-cf45-587a-be880946e881", "device_type": "ios" }, { "channel_id": "13863b3c-f860-4bbf-a9f1-4d785379b8a2", "device_type": "android" } ] ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```python from urbanairship import ( BasicAuthClient, ChannelUninstall ) client = BasicAuthClient( key='', secret='' ) channel_uninstall = ChannelUninstall(client) channel = { "channel_id": 'b8f9b663-0a3b-cf45-587a-be880946e881', "device_type": "ios" } channel_uninstall.uninstall(channel) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') cu = UA::ChannelUninstall.new(client: airship) chans = [{"channel_id" => "b8f9b663-0a3b-cf45-587a-be880946e881", "device_type" => "ios"}, {"channel_id" => "13863b3c-f860-4bbf-a9f1-4d785379b8a2", "device_type" => "android"}] cu.uninstall(channels: chans) ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); Set channels = ImmutableSet.of( new ChannelUninstallDevice("00f74677-4616-4958-bd91-30e949814d2c", ChannelUninstallDeviceType.IOS), new ChannelUninstallDevice("007f7156-9b82-4cb6-a2f9-e2c8e7fce13d", ChannelUninstallDeviceType.ANDROID) ); ChannelUninstallPayload payload = ChannelUninstallPayload.newBuilder() .setChannels(channels) .build(); ChannelUninstallRequest request = ChannelUninstallRequest.newRequest(payload); Response response = client.execute(request); ``` --- # Contacts > Manage Contacts and query for subscription lists, channels, named users, and attributes associated with a Contact. ## Contact association {#associatecontact} Associate a channel, email address, or MSISDN with a Contact. The `contact_id` is created if it does not already exist. ### `POST /api/contacts/associate` {{< note >}} If the `channel_id`, `email_address`, or `msisdn` is already associated with a `contact_id`, this operation will do nothing and return a 200 status code and the existing `contact_id`. {{< /note >}} **Security:** - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): cnt **Request body** Contact association requires a `channel_id`, `email_address`, or `msisdn`. Do not provide more than one identifier type in the same request. You can associate up to 100 Channel IDs to a Contact. Channel creation is asynchronous, so when associating a newly created channel, both a Channel ID and a device type are required to prevent "channel does not exist" errors. **Content-Type:** `application/json` **One of:** - **`channel_id`** `string` **REQUIRED** The Channel ID you want to associate with a Contact. Format: `uuid` Example: `9c36e8c7-5a73-47c0-9716-99fd3d4197d5` - **`contact_id`** `string` **REQUIRED** A string value identifying the user, without leading or trailing whitespace. Min length: 1, Max length: 128 Example: `john_doe` - **`device_type`** `string` The device type of the channel. Possible values: `ios`, `android`, `amazon`, `web`, `open`, `email`, `sms` - **`contact_id`** `string` **REQUIRED** The existing Contact. Min length: 1, Max length: 128 Example: `john_doe` - **`email_address`** `string` **REQUIRED** The email address you want to associate with a Contact. Format: `email` Example: `user@example.com` **Responses** **`200`** The request was accepted. The `contact_id` is returned in the response. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) --- ## Contact disassociation {#disassociatecontact} Disassociates channel from a Contact with the option of also opting out. You can identify a channel by MSISDN, email address, or Channel ID. [Jump to examples ↓](#disassociatecontact-examples) ### `POST /api/contacts/disassociate/{contact_id}` **Security:** - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): cnt **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `contact_id` | `string` | Required | The Contact ID to disassociate from a channel. | **Request body** **Content-Type:** `application/json` - **`channel_id`** `string` The Channel ID to disassociate from the Contact. Format: `uuid` Example: `{{channel_id}}` - **`channel_type`** `string` **REQUIRED** The type of channel. Possible values: `sms`, `email`, `ios`, `android`, `amazon`, `web`, `open` - **`email_address`** `string` The email address to disassociate from the Contact. - **`msisdn`** `string` The mobile phone number to disassociate from the Contact. Must be numeric characters only, without leading zeros. 15 digits maximum. Max length: 15 - **`opt_out`** `boolean` Optional. True if the channel is to be opted out; otherwise false. - **`sender`** `string` A long or short code the app is configured to send from. For example, `12345`. **Responses** **`200`** The request was accepted. Response body: **Content-Type:** `application/json` - **`channel_id`** `string` Identifies the existing unique Channel ID. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`contact`** `string` Identifies the existing unique Contact ID. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`ok`** `boolean` Success. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example dissociate SMS channel from Contact by Channel ID* ```http POST /api/contacts/disassociate/eed87e83-2f2f-4919-bcb0-8c620e0fae40 HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "channel_type": "sms", "channel_id": "c8d58c64-7eb5-40ad-ad51-d39e05335c48" } ``` *Example dissociate SMS channel from Contact by sender ID and MSISDN* ```http POST /api/contacts/disassociate/eed87e83-2f2f-4919-bcb0-8c620e0fae40 HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "channel_type": "sms", "sender": "1234", "msisdn": "15035551234" } ``` *Example dissociate email channel from Contact by email address* ```http POST /api/contacts/disassociate/eed87e83-2f2f-4919-bcb0-8c620e0fae40 HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "channel_type": "email", "email_address": "abc@example.com" } ``` *Example dissociate email channel from Contact by email address with opt_out* ```http POST /api/contacts/disassociate/eed87e83-2f2f-4919-bcb0-8c620e0fae40 HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "channel_type": "email", "email_address": "abc@example.com", "opt_out": true } ``` *Example of a successful response* ```http HTTP/1.1 200 OK Content-Type: application/json { "ok": true, "contact": "eed87e83-2f2f-4919-bcb0-8c620e0fae40", "channel_id": "c8d58c64-7eb5-40ad-ad51-d39e05335c48" } ``` --- ## Contacts tags {#modifycontacttags} Add, remove, or set tags on a Contact. A single request body may contain add and/or remove objects or a single set field. At least one of the add, remove, or set objects must be present in a request. ### `POST /api/contacts/tags/` {{< important >}} A tag must be < 128 characters. A request with one or more tags longer than 128 characters will return a 400 response. We support up to 1,000 tags per Contact. Adding more than 1,000 tags per Contact can cause latency and service interruptions. We strongly recommend removing unused tags whenever possible, and using Custom Events when appropriate. Please [contact Support](https://support.airship.com/) if you believe your use case requires more than 1,000 tags per Contact, and they will help you find an alternative. {{< /important >}} **Security:** - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): cnt **Request body** **Content-Type:** `application/json` - **`add`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Add the list of tags to the Contacts, but do not remove any. If the tags are already present, they are not modified. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`audience`** `object` **REQUIRED** The Contacts you want to associate/disassociate tags with. **OBJECT PROPERTIES** - **`contact_id`** `array[string]` Min items: 1, Max items: 1000 - **`remove`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Remove the list of tags from the Contacts, but do not remove any others. If the tags are not currently present, nothing happens. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`set`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Set these tags for the audience. Any tags previously associated with the audience tags that are not in this current list are removed. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. **Responses** **`200`** If a tag request is partially valid, i.e., at least one tag group exists and is active, a 200 will be returned with a warning in the response about the tag groups that failed to update. The tag groups listed in the warning will be CSV-formatted. Response body: **Content-Type:** `application/json` - **`ok`** `boolean` **REQUIRED** Set to `true` when status code is `200`. - **`tag_warnings`** `string` Warnings encountered when processing tags for this Contact. **`400`** Parsing or validating the request failed. You will see this error if the same tag is present in both the add and remove fields. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) --- ## Look up Contact ID by Channel ID {#getcontactidfromchannelid} Looks up a Contact ID for the given Channel ID. [Jump to examples ↓](#getcontactidfromchannelid-examples) ### `GET /api/contacts/lookup/channel/{channel_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): cnt **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `channel_id` | `string` | Required | The Channel ID for which to retrieve the associated Contact ID. | **Responses** **`200`** The request was accepted. Response body: **Content-Type:** `application/json` - **`contact_id`** `string` **REQUIRED** The resolved Contact ID. Format: `uuid` - **`is_anonymous`** `boolean` **REQUIRED** Specifies whether the Contact is anonymous or not. - **`ok`** `boolean` **REQUIRED** Set to `true` when status code is `200`. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example get Contact ID from a Channel ID * ```http GET /api/contacts/lookup/channel/164c3a13-9c75-4ea9-be2c-1bed2c97f9c3 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "contact_id": "7c24ebdd-ec06-47d4-9a56-ced8611f5b52", "is_anonymous": false } ``` --- ## Look up Contact ID by Named User ID {#getcontactidfromnameduserid} Looks up a Contact ID for the given Named User ID. [Jump to examples ↓](#getcontactidfromnameduserid-examples) ### `GET /api/contacts/lookup/named_user/{named_user_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): cnt **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `named_user_id` | `string` | Required | The URL-encoded Named User ID for which to retrieve the associated Contact ID. | **Responses** **`200`** The request was accepted. Response body: **Content-Type:** `application/json` - **`contact_id`** `string` **REQUIRED** The resolved Contact ID. Format: `uuid` - **`ok`** `boolean` **REQUIRED** Set to `true` when status code is `200`. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example get Contact ID from a Named User ID * ```http GET /api/contacts/lookup/named_user/90ae282f-f56e-4037-8174-482ef7e3e5f4 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "contact_id": "7c24ebdd-ec06-47d4-9a56-ced8611f5b52" } ``` --- ## Scoped Contact batch operations {#performscopedcontactbatchoperations} Performs one or more scoped operations on a Contact in a single request. The body is a scoped array, and each item has a scope and one or more operations. Behavior matches the equivalent single-operation APIs. For each scope: * Subscription list operations are supported. You can subscribe and/or unsubscribe the Contact to/from subscription lists for that scope, which is the same behavior as the subscription list APIs. * Tag operations are not supported. If `tags` is present in any scoped item, the request is rejected with 400 and an error indicating that tags are not allowed in this context. The following apply: * Set operations are not supported. * Failure to authorize on secure tags results in a 200 and warning. * Failure to find any valid tag groups results in a 200 and warning. * Failure to find any valid attributes results in a 200 and warning. [Jump to examples ↓](#performscopedcontactbatchoperations-examples) ### `POST /api/contacts/scoped/{contact_id}` {{< note >}} If you are using a single-channel Preference Center created before October 10, 2022, that has not been [migrated to user-level](/docs/guides/messaging/features/preference-centers/#migrating-to-a-user-level-preference-center), use the [`/api/channels/subscription_lists` endpoint](/docs/developer/rest-api/ua/operations/channels/#modifychannelsubscriptions) to add or remove individual channels to/from your subscription list. {{< /note >}} {{< important >}} The path parameter `contact_id` should be URL-encoded to ensure it is handled correctly. {{< /important >}} **Security:** - [basicAppAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAppAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): cnt **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `contact_id` | `string` | Required | A string (UUID) value identifying the Contact with no leading or trailing whitespace. | **Request body** **Content-Type:** `application/json` - **`scoped`** `array` <[Contacts scoped batch item]({{< ref "/developer/rest-api/ua/schemas/contacts/" >}}#contactsscopedbatchitem)> An array of scopes, tags, and subscription lists. **Responses** **`200`** The request was accepted. Response body: **Content-Type:** `application/json` - **`ok`** `boolean` **REQUIRED** Whether the operation was successful. - **`subscription_list_warnings`** `array[string]` Any warnings related to subscription list operations. - **`tag_warnings`** `array[string]` Any warnings related to tag operations. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example scoped contact batch operations * ```http POST /api/contacts/scoped/77721a11-7ffa-4362-9bdb-f27ca891f9de HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "scoped": [{ "scope": ["web", "email", "app"], "subscription_lists": { "subscribe": ["subscription_1", "subscription_2"], "unsubscribe": ["subscription_3"] } }] } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` --- ## Set or remove attributes on a Contact {#modifycontactattributes} Set or remove attributes on a Contact. A single request body may contain a `set` or `remove` field, or both, or a single `set` field. If both `set` and `remove` fields are present and the intersection of the attributes in these fields is not empty, then a `400` will be returned. If an attribute request is partially valid, i.e., at least one attribute exists, Airship returns a `200` with a warning about the attributes that failed to update. The attributes listed in the `warnings` string will be in CSV format. ### `POST /api/contacts/attributes` {{< note >}} Airship returns a `200` with a warning if you attempt to set attributes on a Contact that does not exist. {{< /note >}} {{< tip >}} If you wish to set attributes on multiple Contact at once, we recommend using [/api/channels/attributes](/docs/developer/rest-api/ua/operations/channels/#modifychannelattributes) which supports an `audience` object in the request body. {{< /tip >}} **Security:** - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): cnt **Request body** **Content-Type:** `application/json` Type: `array` **Responses** **`200`** Success. If an attribute request is partially valid, i.e., at least one attribute exists, Airship returns a `200` with a warning string containing a CSV list of attributes that failed to update. Airship also returns a `200` with a warning if you attempt to set attributes on a `contact_id`, even if the `contact_id` does not exist. Response body: **Content-Type:** `application/json` - **`ok`** `boolean` Set to `true` when status code is `200`. - **`warnings`** `string` Warnings encountered when updating Contact attributes. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) --- # Content > Use the Content API to create content templates that can be sent in pushes and [managed in the Airship dashboard](/guides/personalization/content/templates/). ## Create content template {#createcontenttemplate} Create a new content template. [Jump to examples ↓](#createcontenttemplate-examples) ### `POST /api/content/templates` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): tpl **Request body** A single content template object. **Content-Type:** `application/json` [Content template object]({{< ref "/developer/rest-api/ua/schemas/content-objects/" >}}#contenttemplateobject) **Responses** **`201`** The template was created. Response headers: | Name | Type | Description | |------|------|-------------| | `Location` | `string` | The URI for the template, used for later updates or sends. | Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` **REQUIRED** If `true`, the operation completed successfully and returns an expected response. - **`operation_id`** `string` A unique string identifying the operation, useful for reporting and troubleshooting. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`template_id`** `string` A unique string identifying the template, used to reference it when sending messages and in other operations. Format: `uuid` Example: `0f7704e9-5dc0-4f7d-9964-e89055701b0a` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example create email content template with snippet and feed references* ```http POST /api/content/templates HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "external_id": "welcome_message", "name": "Welcome Message", "description": "Our welcome message", "type": "email", "content": { "subject": "Welcome!", "html_body": "Hi, {{first_name}}! {{>footer}}", "plaintext_body": "Hi, {{first_name}}!" }, "snippet_references": { "snippets": [ { "name": "footer" } ] }, "feed_references": { "feeds": [ { "name": "featured_product" } ] } } ``` ```http HTTP/1.1 201 Created Location: https://go.urbanairship.com/api/content/templates/ef34a8d9-0ad7-491c-86b0-aea74da15161 Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "operation_id" : "9ce808c8-7176-45dc-b79e-44aa74249a5a", "template_id": "ef34a8d9-0ad7-491c-86b0-aea74da15161" } ``` --- ## Create or update content template by external ID {#updatecontenttemplatebyexternalid} Create or update a content template by its external ID. [Jump to examples ↓](#updatecontenttemplatebyexternalid-examples) ### `PUT /api/content/templates/external/{type}/{external_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): tpl **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `type` | `string` | Required | The message type for the template. Possible values: `email`, `sms`, `open`, `app`, `web`, `message_center` | | `external_id` | `string` | Required | The customer-defined external ID of the template. | **Request body** A partially defined content template object. **Content-Type:** `application/json` [Content template object]({{< ref "/developer/rest-api/ua/schemas/content-objects/" >}}#contenttemplateobject) **Responses** **`200`** Returned if the template has been successfully updated. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` **REQUIRED** If `true`, the operation completed successfully and returns an expected response. - **`operation_id`** `string` A unique string identifying the operation, useful for reporting and troubleshooting. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example update content template by external ID* ```http PUT /api/content/templates/external/email/customer-defined-id HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "name": "Welcome Message", "description": "Our welcome message", "content": { "subject": "Welcome!", "html_body": "Hi, {{first_name}}!", "plaintext_body": "Hi, {{first_name}}!" } } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "operation_id" : "9ce808c8-7176-45dc-b79e-44aa74249a5a" } ``` --- ## Delete content template {#deletecontenttemplate} Delete a content template. [Jump to examples ↓](#deletecontenttemplate-examples) ### `DELETE /api/content/templates/{template_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): tpl **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `template_id` | `string` | Required | The UUID of the template. | **Responses** **`200`** The template with the given ID has been successfully deleted. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` **REQUIRED** If `true`, the operation completed successfully and returns an expected response. - **`operation_id`** `string` A unique string identifying the operation, useful for reporting and troubleshooting. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example delete content template* ```http DELETE /api/content/templates/ef34a8d9-0ad7-491c-86b0-aea74da15161 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "operation_id" : "9ce808c8-7176-45dc-b79e-44aa74249a5a" } ``` --- ## Delete content template by external ID {#deletecontenttemplatebyexternalid} Delete a content template. [Jump to examples ↓](#deletecontenttemplatebyexternalid-examples) ### `DELETE /api/content/templates/external/{type}/{external_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): tpl **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `type` | `string` | Required | The message type for the template. Possible values: `email`, `sms`, `open`, `app`, `web`, `message_center` | | `external_id` | `string` | Required | The customer-defined external ID of the template. | **Responses** **`200`** The template with the given external ID has been successfully deleted. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` **REQUIRED** If `true`, the operation completed successfully and returns an expected response. - **`operation_id`** `string` A unique string identifying the operation, useful for reporting and troubleshooting. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example delete content template by external ID* ```http DELETE /api/content/templates/external/email/customer-defined-id HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "operation_id" : "9ce808c8-7176-45dc-b79e-44aa74249a5a" } ``` --- ## List content templates {#listcontenttemplates} List all existing content templates. Returns an array of content template objects in the `content_templates` attribute. [Jump to examples ↓](#listcontenttemplates-examples) ### `GET /api/content/templates` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): tpl **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `page` | `integer` | | Specifies the desired page number. Defaults to 1. | | `page_size` | `integer` | | Specifies how many results to return per page. | | `sort` | `string` | | Specifies the name of the field you want to sort results by. Defaults to `created_at`. Possible values: `created_at`, `modified_at` | | `order` | `string` | | Specifies the sort order as ascending (`asc`) or descending (`desc`). Defaults to `asc`. Possible values: `asc`, `desc` | **Responses** **`200`** Returned on success, with the JSON representation of the content templates in the body of the response. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`content_templates`** `array` <[Content template object]({{< ref "/developer/rest-api/ua/schemas/content-objects/" >}}#contenttemplateobject)> An array of content template objects. - **`count`** `integer` The number of content templates in the current response. This is effectively the page size. - **`next_page`** `string` There might be more than one page of results for this listing. When present, use this URL to fetch the next batch of results. Format: `url` - **`ok`** `boolean` **REQUIRED** Success. - **`prev_page`** `string` Link to the previous page, if available. Format: `url` - **`total_count`** `integer` The total number of content templates. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example list content templates* ```http GET /api/content/templates HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "count": 1, "total_count": 1, "content_templates": [ { "id": "ef34a8d9-0ad7-491c-86b0-aea74da15161", "external_id": "welcome_message", "name": "Welcome Message", "description": "Our welcome message", "type": "email", "content": { "subject": "Welcome!", "html_body": "Hi, {{first_name}}!", "plaintext_body": "Hi, {{first_name}}!" }, "created_at": "2020-08-17T11:10:02Z", "modified_at": "2020-08-17T11:10:02Z" } ], "next_page": null, "prev_page": null } ``` --- ## Look up a content template {#getcontenttemplate} Fetch a single content template using UUID. [Jump to examples ↓](#getcontenttemplate-examples) ### `GET /api/content/templates/{template_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): tpl **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `template_id` | `string` | Required | The UUID of the template. | **Responses** **`200`** Returned on success, with the JSON representation of the template in the body of the response. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`content_template`** `object` <[Content template object]({{< ref "/developer/rest-api/ua/schemas/content-objects/" >}}#contenttemplateobject)> A reusable template containing fields for a message type. Can be referenced by its UUID or a customer-defined external ID. - **`ok`** `boolean` **REQUIRED** If `true`, the operation completed successfully and returns an expected response. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example look up content template* ```http GET /api/content/templates/ef34a8d9-0ad7-491c-86b0-aea74da15161 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "content_template": { "id": "ef34a8d9-0ad7-491c-86b0-aea74da15161", "external_id": "welcome_message", "name": "Welcome Message", "description": "Our welcome message", "type": "email", "content": { "subject": "Welcome!", "html_body": "Hi, {{first_name}}! {{>footer}}", "plaintext_body": "Hi, {{first_name}}!" }, "created_at": "2020-08-17T11:10:02Z", "modified_at": "2020-08-17T11:10:02Z", "snippets": [ { "name": "footer" } ] } } ``` --- ## Look up a content template by external ID {#getcontenttemplatebyexternalid} Fetch a single content template using external ID. [Jump to examples ↓](#getcontenttemplatebyexternalid-examples) ### `GET /api/content/templates/external/{type}/{external_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): tpl **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `type` | `string` | Required | The message type for the template. Possible values: `email`, `sms`, `open`, `app`, `web`, `message_center` | | `external_id` | `string` | Required | The customer-defined external ID of the template. | **Responses** **`200`** Returned on success, with the JSON representation of the template in the body of the response. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`content_template`** `object` <[Content template object]({{< ref "/developer/rest-api/ua/schemas/content-objects/" >}}#contenttemplateobject)> A reusable template containing fields for a message type. Can be referenced by its UUID or a customer-defined external ID. - **`ok`** `boolean` **REQUIRED** If `true`, the operation completed successfully and returns an expected response. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example look up content template by external ID* ```http GET /api/content/templates/external/email/customer-defined-id HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "content_template": { "id": "ef34a8d9-0ad7-491c-86b0-aea74da15161", "external_id": "customer-defined-id", "name": "Welcome Message", "description": "Our welcome message", "type": "email", "content": { "subject": "Welcome!", "html_body": "Hi, {{first_name}}! {{>footer}}", "plaintext_body": "Hi, {{first_name}}!" }, "created_at": "2020-08-17T11:10:02Z", "modified_at": "2020-08-17T11:10:02Z", "snippets": [ { "name": "footer" } ] } } ``` --- ## Update content template {#updatecontenttemplate} Update a content template. [Jump to examples ↓](#updatecontenttemplate-examples) ### `PUT /api/content/templates/{template_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): tpl **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `template_id` | `string` | Required | The UUID of the template. | **Request body** A partially defined content template object. **Content-Type:** `application/json` [Content template object]({{< ref "/developer/rest-api/ua/schemas/content-objects/" >}}#contenttemplateobject) **Responses** **`200`** Returned if the template has been successfully updated. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` **REQUIRED** If `true`, the operation completed successfully and returns an expected response. - **`operation_id`** `string` A unique string identifying the operation, useful for reporting and troubleshooting. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example update content template* ```http PUT /api/content/templates/ef34a8d9-0ad7-491c-86b0-aea74da15161 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "name": "Welcome Message", "description": "Our welcome message", "content": { "subject": "Welcome!", "html_body": "Hi, {{first_name}}!", "plaintext_body": "Hi, {{first_name}}!" } } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "operation_id" : "9ce808c8-7176-45dc-b79e-44aa74249a5a" } ``` --- # Custom Events > User events that occur outside of your app can be submitted to Airship for inclusion in analytics reporting, as triggers for Automation, or for export via Connect. These events can take place on the web, e.g., your website, social media, or in your back office systems such as CRM or POS software. Any event that can be associated with a mobile app user can be submitted as an Airship Custom Event. The events that you submit are associated with channels and are available to use as Custom Event triggers. ## Add Custom Events {#addcustomevents} Submit an externally-generated Custom Event, associated with a Channel ID or Named User, to Airship. You can use these events as Custom Event triggers for Automation or Sequences and can use handlebars to personalize messages using Custom Event properties (information in the `body.properties` object). [Jump to examples ↓](#addcustomevents-examples) ### `POST /api/custom-events` {{< note >}} * Requests complete validation before returning a response. * Requests are authenticated with a bearer token, which can provide access to this resource alone or to this resource and others. * The `name` value inside `body` must not contain any uppercase characters, or the event will be rejected with a 400 status code. {{< /note >}} **Security:** - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): evt **Request headers:** | Name | Type | Required | Description | |------|------|----------|-------------| | `X-UA-Appkey` | `string` | Required | The application key for your project. | **Request body** An array of Custom Event objects. **Content-Type:** `application/json` Type: `array` **Responses** **`200`** Returned on success. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` Success. - **`operation_id`** `string` A unique string identifying the API interaction. You can use the `operation_id` in support requests if something goes wrong. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/custom-events HTTP/1.1 Authorization: Bearer X-UA-Appkey: Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json [ { "occurred": "2020-05-02T02:31:22", "user": { "named_user_id": "hugh.manbeing" }, "body": { "name": "purchased", "value": 239.85, "transaction": "886f53d4-3e0f-46d7-930e-c2792dac6e0a", "interaction_id": "your.store/us/en_us/pd/shoe/pid-11046546/pgid-10978234", "interaction_type": "url", "properties": { "description": "Sneaker purchase", "brand": "Victory Sneakers", "colors": [ "red", "blue" ], "items": [ { "text": "New Line Sneakers", "price": "$ 79.95" }, { "text": "Old Line Sneakers", "price": "$ 79.95" }, { "text": "Blue Line Sneakers", "price": "$ 79.95" } ], "name": "Hugh Manbeing", "userLocation": { "state": "CO", "zip": "80202" } }, "session_id": "22404b07-3f8f-4e42-a4ff-a996c18fa9f1" } } ] ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "8c61c0c4-95b0-45a6-bc38-733f7fcb8979" } ``` ```python from datetime import datetime from urbanairship import ( BearerTokenClient, CustomEvent ) client = BearerTokenClient( app_key='', token='' ) event = CustomEvent( client=client, name='purchased', user={'named_user_id': 'hugh.manbeing'}, interaction_type='url', interaction_id='your.store/us/en_us/pd/shoe/pid-11046546/pgid-10978234', value=239.85, transaction='886f53d4-3e0f-46d7-930e-c2792dac6e0a', session_id='22404b07-3f8f-4e42-a4ff-a996c18fa9f1', properties={ 'description': 'Sneaker purchase', 'brand': 'Victory Sneakers', 'colors': ['red', 'blue'], 'items': [ {'text': 'New Line Sneakers', 'price': '$ 79.95'}, {'text': 'Old Line Sneakers', 'price': '$ 79.95'}, {'text': 'Blue Line Sneakers', 'price': '$ 79.95'} ], 'name': 'Hugh Manbeing', 'userLocation': { 'state': 'CO', 'zip': '80202' } }, occurred=datetime(2020, 5, 2, 2, 31, 22) ) response = event.send() ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .setBearerToken("") .build(); CustomEventUser customEventUser = CustomEventUser.newBuilder() .setNamedUserId("hugh.manbeing") .build(); CustomEventPropertyValue customEventProperty = CustomEventPropertyValue.of("Victory Sneakers"); List items = new ArrayList<>(); items.add(CustomEventPropertyValue.of("New Line Sneakers")); items.add(CustomEventPropertyValue.of("Old Line Sneakers")); DateTime occurred = new DateTime(2020, 05, 02, 02, 31, 22, DateTimeZone.UTC); CustomEventBody customEventBody = CustomEventBody.newBuilder() .setName("purchased") .addPropertiesEntry("brand", customEventProperty) .addPropertiesEntry("items", CustomEventPropertyValue.of(items)) .build(); CustomEventPayload customEventPayload = CustomEventPayload.newBuilder() .setCustomEventBody(customEventBody) .setCustomEventUser(customEventUser) .setOccurred(occurred) .build(); CustomEventRequest customEventRequest = CustomEventRequest.newRequest(customEventPayload); Response response = client.execute(customEventRequest); ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', token: '') example_events = [ UA.custom_events( body: UA.custom_events_body( interaction_id: "api/ua/#schemas-customeventobject", interaction_type: "url", name: "example", properties: { "who" => "Alf", "where" => "In the garage!", "from" => "Melmac" }, session_id: "8d168d40-bc9b-4359-800c-a546918354ac", transaction: "d768f61f-73ba-495f-9e16-b3b9c3b598b7", value: 1 ), occurred: "2021-10-01T00:00:00", user: UA.custom_events_user(named_user_id: "Gordon Shumway") ) ] event = Urbanairship::CustomEvents::CustomEvent.new(client: airship) event.events = example_events event.create ``` --- # Data Privacy Laws Compliance > Use Contact Management to record data privacy requests for your customers. ## Named Users uninstall {#uninstallnameduser} Disassociate and delete all channels associated with the named_user_id(s) and also delete the named_user_id(s). This call removes all channels associated with a Named User from Airship systems in compliance with data privacy laws. Uninstalling channels also removes accompanying analytic data (including Performance Analytics) from the system. See [Individual Data Privacy Rights Under Data Privacy Laws](/docs/guides/audience/privacy/individual-data-privacy/) for more information about data privacy law compliance. [Jump to examples ↓](#uninstallnameduser-examples) ### `POST /api/named_users/uninstall` {{< note >}} Channel uninstallation, like channel creation, is an asynchronous operation and may take some time to complete. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): nu **Request body** **Content-Type:** `application/json` - **`named_user_id`** `array[string]` **REQUIRED** Array of strings representing the named_user_id(s) you wish to be uninstalled. Must have between 1 to 100 items in the array with a 128 character/byte maximum per item. Min items: 1, Max items: 100 **Responses** **`200`** All channels have been deleted and disassociated from the Named User. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example delete all users and their associated channels* ```http POST /api/named_users/uninstall HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "named_user_id": ["user-id-1234","user-id-5678"] } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```python from urbanairship import ( BasicAuthClient, NamedUser ) client = BasicAuthClient( key='', secret='' ) response = NamedUser.uninstall( client=client, named_users=["user-id-1234", "user-id-5678"] ) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') named_user_uninstall = UA::NamedUserUninstaller.new(client: airship) named_user_uninstall.named_user_ids = ['user-id-1234'] named_user_uninstall.uninstall ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); NamedUserUninstallRequest namedUserUninstallRequest = NamedUserUninstallRequest .newUninstallRequest(ImmutableList.of("user-id-1234","user-id-5678")); Response response = client.execute(namedUserUninstallRequest); ``` --- ## Uninstall channels {#uninstallchannels} Uninstalls a channel, removing it and all accompanying analytic data (including Performance Analytics) from Airship systems in accordance with data privacy law compliance. Uninstallation is handled automatically by the Airship SDK and push systems. If a user decides to opt in to communications again (either by using your app or other user preferences), they will create a new channel and a new set of analytic data. The value of a Channel ID may be the same as before however none of the associated metadata will persist when a user opts in again. A new Channel ID will be created if the user clears their browser’s cookies and data, deletes and reinstalls the app, etc. See [Individual Data Privacy Rights Under Data Privacy Laws](/docs/guides/audience/privacy/individual-data-privacy/) for more information about data privacy law compliance. [Jump to examples ↓](#uninstallchannels-examples) ### `POST /api/channels/uninstall` {{< note >}} Channel uninstallation, like channel creation, is an asynchronous operation and may take some time to complete. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** **Content-Type:** `application/json` Type: `array` **Responses** **`202`** Returns OK for success. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/uninstall HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json [ { "channel_id": "b8f9b663-0a3b-cf45-587a-be880946e881", "device_type": "ios" }, { "channel_id": "13863b3c-f860-4bbf-a9f1-4d785379b8a2", "device_type": "android" } ] ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```python from urbanairship import ( BasicAuthClient, ChannelUninstall ) client = BasicAuthClient( key='', secret='' ) channel_uninstall = ChannelUninstall(client) channel = { "channel_id": 'b8f9b663-0a3b-cf45-587a-be880946e881', "device_type": "ios" } channel_uninstall.uninstall(channel) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') cu = UA::ChannelUninstall.new(client: airship) chans = [{"channel_id" => "b8f9b663-0a3b-cf45-587a-be880946e881", "device_type" => "ios"}, {"channel_id" => "13863b3c-f860-4bbf-a9f1-4d785379b8a2", "device_type" => "android"}] cu.uninstall(channels: chans) ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); Set channels = ImmutableSet.of( new ChannelUninstallDevice("00f74677-4616-4958-bd91-30e949814d2c", ChannelUninstallDeviceType.IOS), new ChannelUninstallDevice("007f7156-9b82-4cb6-a2f9-e2c8e7fce13d", ChannelUninstallDeviceType.ANDROID) ); ChannelUninstallPayload payload = ChannelUninstallPayload.newBuilder() .setChannels(channels) .build(); ChannelUninstallRequest request = ChannelUninstallRequest.newRequest(payload); Response response = client.execute(request); ``` --- # Email > Register email channels, set opt-in status, and manipulate tags on email channels. ## Create email attachment {#createemailattachment} Create attachments by `POST`ing to the attachments URI. The body of the request must be a JSON object describing and including the contents of a file to attach. [Jump to examples ↓](#createemailattachment-examples) ### `POST /api/attachments` {{< important >}} * Attachments can be used for `transactional` sends only, not `commercial`. * Attachments cannot be used in Automations. * Attachment size is limited to 2.5 MB per attachment, with a 20 MB content size limit on each message, including content body and all attachments. * Attachment count is limited to 10 per email. * Sending attachments with malicious content is strictly prohibited. This is enforced in part by blocking file types with .bat and .exe extensions. * Attachments have a TTL (Time To Live) of 60 days. {{< /important >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): att **Request body** **Content-Type:** `application/json` - **`content_type`** `string` **REQUIRED** The mimetype of the uploaded file including the charset parameter, if needed. Example: `"text/plain; charset=\"UTF-8\""` Max length: 100 - **`data`** `string` **REQUIRED** Base64-encoded bytes of the file contents representing a maximum of 2.5 MiB of data when decoded. Padding with `=` chars is optional. - **`filename`** `string` **REQUIRED** The name of the uploaded file (max 255 UTF-8 bytes). Multiple files with the same name are allowed in separate requests. **Responses** **`201`** The email attachment was created. The response body will contain the IDs of the created attachments. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`attachment_id`** `array[string]` The attachment ID for a newly-created attachment. Reference this ID in the `attachments` list in the [Email overrides](/docs/developer/rest-api/ua/schemas/platform-overrides/#emailoverrideobject). - **`ok`** `boolean` Either `true` or `false`. Represents if the operation completed successfully or not. If false, other properties defined here will not necessarily be present. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** The application does not have the proper entitlement to create attachments. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example create email attachment* ```http POST /attachments HTTP/1.1 Authorization: Bearer Content-Type: application/json Accept: application/vnd.urbanairship+json; version=3 { "filename": "rickroll.png", "content_type": "text/plain; charset=\"UTF-8\"", "data": "iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAIAAADTED8xAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8..." } ``` ```http HTTP/1.1 201 Accepted Data-Attribute: attachment_id Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "attachment_ids": [ "b0c46a8d-b701-441b-9d6e-147c183b28ca" ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); EmailAttachmentRequest emailAttachmentRequest = EmailAttachmentRequest.newRequest() .setContentType("text/plain; charset=\"UTF-8\"") .setData("iBORw0KGgoAAAANSUhEUgAAAQAAAAEACAIAAADTED8xAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8...") .setFilename("rickroll.png"); Response response = client.execute(emailAttachmentRequest); ``` ```python from urbanairship import ( BearerTokenClient, EmailAttachment ) client = BearerTokenClient( app_key='', token='' ) attachment = EmailAttachment( client=client, filename='rickroll.png', content_type='image/png; charset="UTF-8"', filepath='path/to/never_gonna.png' ) response = attachment.post() print(response.get('attachment_ids')) ``` --- ## Custom unsubscribe email channel {#customunsubscribeemailchannel} Opts-out an email address using a custom unsubscribe token. Requires [Custom Unsubscribe](/docs/developer/api-integrations/email/custom-unsubscribe-pages/) be enabled for your project. This endpoint is public and does not require authentication. [Jump to examples ↓](#customunsubscribeemailchannel-examples) ### `GET /api/channels/email/custom-unsubscribe` **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `ua_unsubscribe_token` | `string` | Required | The token for the unsubscribe request. | | `ua_redirect` | `string` | | URL of the page to redirect to after unsubscribe. A default confirmation page will be used if not provided. | **Responses** **`302`** The channel was successfully opted out and will be redirected to a confirmation page. Response headers: | Name | Type | Description | |------|------|-------------| | `Location` | `string` | URL of the page to redirect to after unsubscribe. | **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/channels/email/custom-unsubscribe?ua_redirect=https://example.com/success.html&ua_unsubscribe_token=eyJhcHBfa2V5IjoiVmwwd3lHOGtTeUN5T1VXOThXajR4ZyIsImNhbXBhaWducyI6W10sInB1c2hfaWQiOiJlY2U0MDliMC0yNzYyLTExZWUtYjE4Ny0wMjQyNDkzZjM2MTkiLCJtZXNzYWdlX3R5cGUiOiJjb21tZXJjaWFsIiwiY2hhbm5lbF9pZCI6Ik9IWWdxTDJfU3FHMTRQZWlfWjV2QkEifQ%3D%3D HTTP/1.1 Accept: */* ``` ```http HTTP/1.1 302 Found Location: https://example.com/success.html ``` --- ## Email tags {#modifyemailchanneltags} Add, remove, or set tags for a single email channel. [Jump to examples ↓](#modifyemailchanneltags-examples) ### `POST /api/channels/email/tags` {{< important >}} A tag must be < 128 characters. A request with one or more tags longer than 128 characters will return a 400 response. We support up to 1,000 tags per channel. Adding more than 1,000 tags per channel can cause latency and service interruptions. We strongly recommend removing unused tags whenever possible, and using Custom Events when appropriate. Please [contact Support](https://support.airship.com/) if you believe your use case requires more than 1,000 tags per channel, and they will help you find an alternative. {{< /important >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** A single request body can contain an `add` and/or `remove` field or a single `set` field. One or more of the `add`, `remove`, or `set` keys must be present in the request. **Content-Type:** `application/json` - **`add`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Adds the specified tags to the channel. Tags that are already present are not modified/removed as a result of this operation. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`audience`** `object` **REQUIRED** Specifies the email address you want to perform tag operations against. Must contain a single `email_address` key. **OBJECT PROPERTIES** - **`email_address`** `string` **REQUIRED** The email address you want to modify tags for. Accepts a single string value representing an email address. Example: `name@example.com` - **`remove`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Removes the specified tags from the channel. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`set`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Assigns a list of tags exactly. Any previously set tags that are not in this current list are removed. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. **Responses** **`200`** Returns OK for success. If a tag request is partially valid, i.e., at least one tag group exists and is active, a 200 will be returned with a warning in the response about the tag groups that failed to update. The tag groups listed in the warning will be CSV-formatted. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/email/tags HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "email_address": "name@example.com" }, "add": { "my_fav_tag_group1": ["tag1", "tag2", "tag3"], "my_fav_tag_group2": ["tag1", "tag2", "tag3"], "my_fav_tag_group3": ["tag1", "tag2", "tag3"] } } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); EmailTagRequest request = EmailTagRequest.newRequest(); emailTagRequest.addEmailChannel("name@example.com") .addTags("my_fav_tag_group1", ImmutableSet.of("tag1", "tag2", "tag3")) .addTags("my_fav_tag_group2", ImmutableSet.of("tag1", "tag2", "tag3")) .addTags("my_fav_tag_group3", ImmutableSet.of("tag1", "tag2", "tag3")); Response response = client.execute(request); ``` ```python from urbanairship import ( BearerTokenClient, EmailTags ) client = BearerTokenClient( app_key='', token='' ) # replaces all existing tags on an email channel email_tags = EmailTags(airship=client, address='name@example.com') email_tags.set(group='my_tag_group', tags=['one', 'two', 'three']) email_tags.send() # adds and removes tags from an email channel email_tags = EmailTags(airship=client, address='name@example.com') email_tags.remove(group='my_tag_group', tags=['one', 'two', 'three']) email_tags.add(group='my_tag_group', tags=['some', 'new', 'tags']) email_tags.send() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') email_tags = UA::EmailTags.new(client: airship) #set an audience email_tags.set_audience(email_address: 'name@example.com') #add a tag email_tags.add(group_name: 'my_fav_tag_group1', tags: 'tag2') #remove a tag email_tags.remove(group_name: 'my_fav_tag_group1', tags: 'tag1') email_tags.send_request ``` --- ## Look up an email address {#getemailchannel} Returns a channel by email address. For security, email addresses are one-way hashed and aren't returned when you look up a channel by ID. Use this endpoint to find a channel belonging to a particular email address. You may need to escape the `@` character in URLs using`%40`. [Jump to examples ↓](#getemailchannel-examples) ### `GET /api/channels/email/{email}` {{< note >}} Emails with an `opted_out` date that is after or equal to the `opted_in` date will not be sent for that channel. A `commercial_opted_in` date is required for sending commercial emails. Transactional emails do not require a `transactional_opted_in`. This field is used in the case where a user has unsubscribed to transactional email and would like to reassert consent to receive transactional emails. The `opt_in` property is always set to true for an email channel, so it should be ignored. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `email` | `string` | Required | The email address of the channel you want to look up. | **Responses** **`200`** A channel exists for the email address Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`channel`** `object` <[Channel listing object]({{< ref "/developer/rest-api/ua/schemas/channels/" >}}#channellistingobject)> Describes a channel listing object. - **`ok`** `boolean` Success. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/channels/email/name%40example.com HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "channel": { "channel_id": "01234567-890a-bcde-f012-3456789abc0", "device_type": "email", "installed": true, "created": "2020-08-08T20:41:06", "named_user_id": "some_id_that_maps_to_your_systems", "email_address": "name@example.com", "tag_groups": { "tag_group_1": ["tag1", "tag2"], "tag_group_2": ["tag1", "tag2"] }, "address": null, "opt_in": true, "commercial_opted_in": "2020-10-28T10:34:22", "commercial_opted_out": "2020-06-03T09:15:00", "transactional_opted_in": "2020-10-28T10:34:22", "open_tracking_opted_in": "2022-12-11T00:00:00", "click_tracking_opted_in": "2022-12-11T00:00:00", "open_tracking_opted_out": "2022-12-12T00:00:00", "click_tracking_opted_out": "2022-12-12T00:00:00", "last_registration": "2020-05-01T18:00:27" } } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); ChannelRequest channelRequest = ChannelRequest.newEmailLookupRequest("name@example.com"); Response response = client.execute(channelRequest); ``` ```python from urbanairship import ( BearerTokenClient, Email ) client = BearerTokenClient( app_key='', token='' ) response = Email.lookup(airship=client, address='name@example.com') ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') email_channel = UA::Email.new(client: airship) email_channel.address = 'name@example.com' email_channel.lookup ``` --- ## Register email channel {#registeremailchannel} Create a new email channel or update an existing channel. If you provide the email address of an existing channel, the call is treated as a PUT. To update the address of an existing channel, see the [Replace Email Channel](/docs/developer/rest-api/ua/operations/email/#replaceemailchannel) endpoint. [Jump to examples ↓](#registeremailchannel-examples) ### `POST /api/channels/email` {{< note >}} Channel creation is asynchronous, so when associating a newly created channel, both a Channel ID and a device type are required to prevent "channel does not exist" errors. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** A single email channel object. **Content-Type:** `application/json` - **`attributes`** `object` An optional object containing the customer-provided attributes associated with the email. - **`channel`** `object` **REQUIRED** **OBJECT PROPERTIES** - **`address`** `string` **REQUIRED** The email address being registered. Example: `name@example.com` - **`click_tracking_opted_in`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user opted in to click tracking. Format: `date-time` - **`click_tracking_opted_out`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user opted out of click tracking. Format: `date-time` - **`commercial_opted_in`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user gave explicit permission to receive commercial emails. Format: `date-time` - **`commercial_opted_out`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user explicitly denied permission to receive commercial emails. Format: `date-time` - **`locale_country`** `string` The device property tag related to locale country setting. Example: `US` - **`locale_language`** `string` The device property tag related to locale language setting. Example: `en` - **`open_tracking_opted_in`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user opted in to open tracking. Format: `date-time` - **`open_tracking_opted_out`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user opted out of open tracking. Format: `date-time` - **`suppression_state`** `string` If an email channel is suppressed, the reason for its suppression. Email channels with any suppression state set will not have any delivery to them fulfilled. If a more specific reason is not known, use `imported`. Possible values: `spam_complaint`, `commercial_spam_complaint`, `bounce`, `imported` - **`timezone`** `string` The device property tag related to time zone setting. Example: `America/Los_Angeles` - **`transactional_opted_in`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user gave explicit permission to receive transactional emails. Users do not need to opt-in to receive transactional emails unless they have previously opted out. Format: `date-time` - **`transactional_opted_out`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user explicitly denied permission to receive transactional emails. Format: `date-time` - **`type`** `string` **REQUIRED** The type of channel you are registering. Possible values: `email` Example: `email` - **`opt_in_mode`** `string` The opt-in mode for registering the channel. `classic` is the default when unspecified, `double` creates a `double_opt_in` event. Possible values: `classic`, `double` Example: `double` - **`properties`** `object` An object containing event properties. You can use these properties to filter the double opt-in event and reference them in your message content by using handlebars. Items in the `properties` object are limited to a 255-character maximum string length. Example: `[object Object]` - **`tag_operations`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Optionally one or more tag group objects associated with the email. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. **Responses** **`200`** An existing email channel was found matching the address and was updated. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`attributes`** `object` **OBJECT PROPERTIES** - **`ok`** `boolean` If `true`, the attributes were set correctly. - **`channel_id`** `string` A unique string identifying the email channel. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`ok`** `boolean` **REQUIRED** If `true`, the operation was successful. If `false`, other properties defined here will not necessarily be present. - **`tags`** `object` **OBJECT PROPERTIES** - **`ok`** `boolean` If `true`, the tags were set correctly. **`201`** The email channel was created. Response headers: | Name | Type | Description | |------|------|-------------| | `Location` | `string` | The newly created email channel. | Response body: **Content-Type:** `text/plain` - **`channel_id`** `string` A unique string identifying the email channel. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`ok`** `boolean` **REQUIRED** Either `true` or `false`. Represents if the operation completed successfully or not. If false, other properties defined here will not necessarily be present. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/email HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "channel" : { "type": "email", "commercial_opted_in": "2020-10-28T10:34:22", "open_tracking_opted_in": "2022-12-11T00:00:00", "click_tracking_opted_in": "2022-12-11T00:00:00", "address": "name@example.com", "timezone" : "America/Los_Angeles", "locale_country" : "US", "locale_language" : "en" }, "opt_in_mode" : "classic", "properties" : { "interests" : "newsletter" }, "tag_operations": { "add": { "my_fav_tag_group1": ["tag1", "tag2", "tag3"], "my_fav_tag_group2": ["tag1", "tag2", "tag3"], "my_fav_tag_group3": ["tag1", "tag2", "tag3"] } }, "attributes": { "my_fav_attribute1": "attribute1", "my_fav_attribute2": "attribute2" } } ``` ```http HTTP/1.1 201 Created Location: https://go.urbanairship.com/api/channels/251d3318-b3cb-4e9f-876a-ea3bfa6e47bd Content-Type: application/json { "ok": true, "channel_id": "251d3318-b3cb-4e9f-876a-ea3bfa6e47bd", "attributes": {"ok": true}, "tags": {"ok": true} } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); RegisterEmailChannel emailChannel = RegisterEmailChannel.newBuilder() .setAddress("name@example.com") .setEmailOptInLevel(OptInLevel.EMAIL_COMMERCIAL_OPTED_IN, "2020-10-28T10:34:22") .setEmailOptInMode(OptInMode.CLASSIC) .addProperty("interests","newletter") .build(); RegisterEmailChannelRequest request = RegisterEmailChannelRequest.newRequest(emailChannel); Response response = client.execute(request); ``` ```python from urbanairship import ( BearerTokenClient, Email ) client = BearerTokenClient( app_key='', token='' ) email = Email( client=client, address='name@example.com', commercial_opted_in='2020-10-28T10:34:22', timezone='America/Los_Angeles', locale_country='US', locale_language='en' ) response = email.register() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') email_channel = UA::Email.new(client: airship) email_channel.type = 'email' email_channel.commercial_opted_in = '2020-10-28T10:34:22' email_channel.address = 'name@example.com' email_channel.timezone = 'America/Los_Angeles' email_channel.locale_country = 'US' email_channel.locale_language = 'en' email_channel.register ``` --- ## Remove suppression from an email channel {#unsuppressemailchannel} Remove the suppression reason for an existing email channel, allowing the channel to receive emails, depending on the channel's commercial and transactional opt-in status. [Jump to examples ↓](#unsuppressemailchannel-examples) ### `POST /api/channels/email/unsuppress` {{< important >}} Calling this endpoint will not modify commercial or transactional opt-in status to opted-in. {{< /important >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** **Content-Type:** `application/json` - **`address`** `string` **REQUIRED** The email address for the channel to be unsuppressed. Example: `user@example.com` **Responses** **`202`** Returns OK for success. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/email/unsuppress HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "address": "name@example.com" } ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); UnsuppressEmailChannelRequest request = UnsuppressEmailChannelRequest.newRequest("name@example.com"); Response response = client.execute(request); ``` --- ## Replace email channel {#replaceemailchannel} Creates a new email channel in place of the provided channel. You may use this endpoint to change a contact's email address. When called with an email channel, this endpoint will: * Register a new channel * Associate the new email channel with the same user as the source channel * Uninstall the source channel [Jump to examples ↓](#replaceemailchannel-examples) ### `POST /api/channels/email/replace/{channel_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `channel_id` | `string` | Required | The email `channel_id` you want to modify. | **Request body** A single email channel object. **Content-Type:** `application/json` - **`attributes`** `object` An optional object containing the customer-provided attributes associated with the email. - **`channel`** `object` **REQUIRED** **OBJECT PROPERTIES** - **`address`** `string` **REQUIRED** The email address being registered. Example: `name@example.com` - **`click_tracking_opted_in`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user opted in to click tracking. Format: `date-time` - **`click_tracking_opted_out`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user opted out of click tracking. Format: `date-time` - **`commercial_opted_in`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user gave explicit permission to receive commercial emails. Format: `date-time` - **`commercial_opted_out`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user explicitly denied permission to receive commercial emails. Format: `date-time` - **`locale_country`** `string` The device property tag related to locale country setting. Example: `US` - **`locale_language`** `string` The device property tag related to locale language setting. Example: `en` - **`open_tracking_opted_in`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user opted in to open tracking. Format: `date-time` - **`open_tracking_opted_out`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user opted out of open tracking. Format: `date-time` - **`suppression_state`** `string` If an email channel is suppressed, the reason for its suppression. Email channels with any suppression state set will not have any delivery to them fulfilled. If a more specific reason is not known, use `imported`. Possible values: `spam_complaint`, `commercial_spam_complaint`, `bounce`, `imported` - **`timezone`** `string` The device property tag related to time zone setting. Example: `America/Los_Angeles` - **`transactional_opted_in`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user gave explicit permission to receive transactional emails. Users do not need to opt-in to receive transactional emails unless they have previously opted out. Format: `date-time` - **`transactional_opted_out`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user explicitly denied permission to receive transactional emails. Format: `date-time` - **`type`** `string` **REQUIRED** The type of channel you are registering. Possible values: `email` Example: `email` - **`opt_in_mode`** `string` The opt-in mode for registering the channel. `classic` is the default when unspecified, `double` creates a `double_opt_in` event. Possible values: `classic`, `double` Example: `double` - **`properties`** `object` An object containing event properties. You can use these properties to filter the double opt-in event and reference them in your message content by using handlebars. Items in the `properties` object are limited to a 255-character maximum string length. Example: `[object Object]` - **`tag_operations`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Optionally one or more tag group objects associated with the email. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. **Responses** **`201`** The operation was successful. Response headers: | Name | Type | Description | |------|------|-------------| | `Location` | `string` | The newly created email channel. | Response body: **Content-Type:** `text/plain` - **`channel_id`** `string` A unique string identifying the email channel. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`ok`** `boolean` Either `true` or `false`. Represents if the operation completed successfully or not. If false, other properties defined here will not necessarily be present. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/email/replace/9c36e8c7-5a73-47c0-9716-99fd3d4197d5 HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "channel" : { "type": "email", "commercial_opted_in": "2022-02-13T11:58:59", "address": "name@example.com", "timezone" : "America/Los_Angeles", "locale_country" : "US", "locale_language" : "en" } } ``` ```http HTTP/1.1 201 Created Content-Type: application/json Location: https://go.urbanairship.com/api/channels/251d3318-b3cb-4e9f-876a-ea3bfa6e47bd { "ok": true, "channel_id": "251d3318-b3cb-4e9f-876a-ea3bfa6e47bd" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); RegisterEmailChannel emailChannel = RegisterEmailChannel.newBuilder() .setAddress("name@example.com") .setEmailOptInLevel(OptInLevel.EMAIL_COMMERCIAL_OPTED_IN, "2022-02-13T11:58:59") .setTimeZone("America/Los_Angeles") .setLocaleCountry("US") .setLocaleLanguage("en") .build(); ReplaceEmailChannelRequest request = ReplaceEmailChannelRequest.newRequest("9c36e8c7-5a73-47c0-9716-99fd3d4197d5", emailChannel); Response response = client.execute(request); ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') email_channel = UA::Email.new(client: airship) email_channel.channel_id = '251d3318-b3cb-4e9f-876a-ea3bfa6e47bd' email_channel.address = 'tommy@example.com' email_channel.type = 'email' email_channel.commercial_opted_in = '2020-10-28T10:34:22' email_channel.replace ``` --- ## Suppress an email channel {#suppressemailchannel} Suppress an existing email channel, disallowing any future delivery from being fulfilled for the channel. [Jump to examples ↓](#suppressemailchannel-examples) ### `POST /api/channels/email/suppress` {{< note >}} Suppression state types that only apply to commercial messages, such as `commercial_spam_complaint`, cannot overwrite suppression state types that also apply to transactional messages. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** **Content-Type:** `application/json` - **`address`** `string` **REQUIRED** The email address for the channel to be suppressed. Example: `user@example.com` - **`reason`** `string` **REQUIRED** The reason for suppressing the channel. If there is no specific reason, use `imported`. Possible values: `spam_complaint`, `commercial_spam_complaint`, `bounce`, `imported` Example: `spam_complaint` **Responses** **`202`** Returns OK for success. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/email/suppress HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "address": "name@example.com", "reason": "spam_complaint" } ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); SuppressEmailChannelRequest request = SuppressEmailChannelRequest.newRequest("name@example.com","reason"); Response response = client.execute(request); ``` --- ## Uninstall email channel {#uninstallemailchannel} **Removes an email address from Airship. Use with caution.** If the uninstalled email address opts-in again, it might generate a new channel_id. If a user generates a new `channel_id` when they opt-in again, the new `channel_id` cannot be reassociated with any opt-in information, tags, Named Users, Performance Analytics reports, or other information from the that belonged to the previously-uninstalled email channel. [Jump to examples ↓](#uninstallemailchannel-examples) ### `POST /api/channels/email/uninstall` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** An email address of the channel to uninstall. **Content-Type:** `application/json` - **`email_address`** `string` **REQUIRED** The email address of the channel to uninstall. Example: `name@example.com` **Responses** **`202`** Returns OK for success. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/email/uninstall HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "email_address": "name@example.com" } ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); UninstallEmailChannel uninstallEmailChannel = UninstallEmailChannel.newBuilder() .setEmailAddress("name@example.com") .build(); UninstallEmailChannelRequest request = UninstallEmailChannelRequest.newRequest(uninstallEmailChannel); Response response = client.execute(request); ``` ```python from urbanairship import ( BearerTokenClient, Email ) client = BearerTokenClient( app_key='', token='' ) email = Email(airship=client, address='name@example.com') resp = email.uninstall() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') email_channel = UA::Email.new(client: airship) email_channel.address = 'name@example.com' email_channel.uninstall ``` --- ## Update an email channel {#updateemailchannel} Update an email channel. You can use this endpoint to update the subscription/unsubscription values. [Jump to examples ↓](#updateemailchannel-examples) ### `PUT /api/channels/email/{email}` {{< important >}} If you provide an `address` in this request, it must be the one that is associated with the channel you are updating. You may not update the user's email address with this endpoint. {{< /important >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `email` | `string` | Required | The email `channel_id` you want to modify. | **Request body** **Content-Type:** `application/json` - **`channel`** `object` **REQUIRED** **OBJECT PROPERTIES** - **`address`** `string` The email address associated with the email channel. If provided, it must match the existing email address or the request will be rejected with a 400 status code. Example: `tommy@example.com` - **`commercial_opted_in`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user gave explicit permission to receive commercial emails. Format: `date-time` - **`commercial_opted_out`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user explicitly denied permission to receive commercial emails. Format: `date-time` - **`device_type`** `string` The type of channel you are updating. Possible values: `email` Example: `email` - **`locale_country`** `string` The device property tag related to locale country setting. Example: `US` - **`locale_language`** `string` The device property tag related to locale language setting. Example: `en` - **`suppression_state`** `string` If an email channel is suppressed, the reason for its suppression. Email channels with any suppression state set will not have any delivery to them fulfilled. If a more specific reason is not known, use `imported`. Possible values: `spam_complaint`, `commercial_spam_complaint`, `bounce`, `imported` - **`timezone`** `string` The device property tag related to time zone setting. Example: `America/Los_Angeles` - **`transactional_opted_in`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user gave explicit permission to receive transactional emails. Users do not need to opt-in to receive transactional emails unless they have previously opted out. Format: `date-time` - **`transactional_opted_out`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when a user explicitly denied permission to receive transactional emails. Format: `date-time` **Responses** **`200`** The email channel was updated. Response headers: | Name | Type | Description | |------|------|-------------| | `Location` | `string` | The updated email channel. | Response body: **Content-Type:** `text/plain` - **`channel_id`** `string` A unique string identifying the email channel. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`ok`** `boolean` Either `true` or `false`. Represents if the operation completed successfully or not. If false, other properties defined here will not necessarily be present. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example update email address* ```http PUT /api/channels/email/251d3318-b3cb-4e9f-876a-ea3bfa6e47bd HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "channel" : { "device_type": "email", "address": "tommy@example.com", "commercial_opted_in": "2020-10-28T10:34:22" } } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 Location: https://go.urbanairship.com/api/channels/251d3318-b3cb-4e9f-876a-ea3bfa6e47bd { "ok": true, "channel_id": "251d3318-b3cb-4e9f-876a-ea3bfa6e47bd" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); UpdateEmailChannel updateEmailChannel = UpdateEmailChannel.newBuilder() .setAddress("name@example.com") .setEmailOptInLevel(OptInLevel.EMAIL_COMMERCIAL_OPTED_IN, "2021-10-28T10:34:22") .setEmailOptInLevel(OptInLevel.EMAIL_TRANSACTIONAL_OPTED_IN,"2021-10-28T10:34:22") .build(); UpdateEmailChannelRequest updateEmailChannelRequest = UpdateEmailChannelRequest.newRequest("6c8f1d3a-64d8-4ef9-b7a1-9b128013327e", updateEmailChannel); Response response = client.execute(updateEmailChannelRequest); ``` ```python from urbanairship import ( BearerTokenClient, Email ) client = BearerTokenClient( app_key='', token='' ) email = Email( client=client, address='tommy@example.com', commercial_opted_in='2020-10-28T10:34:22' ) response = email.update(channel_id='251d3318-b3cb-4e9f-876a-ea3bfa6e47bd') ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') email_channel = UA::Email.new(client: airship) email_channel.channel_id = '251d3318-b3cb-4e9f-876a-ea3bfa6e47bd' email_channel.type = 'email' email_channel.commercial_opted_in = '2020-10-28T10:34:22' email_channel.update ``` --- # Named Users > A Named User is a proprietary identifier that maps customer-chosen IDs, e.g., CRM data, to Channels. It is useful to think of a Named User as an individual consumer who might have more than one mobile device registered with your app. For example, Named User "john_doe_123" might have a personal Android phone and an iPad, on both of which he has opted in for push notifications. If you want to reach John on both devices, associate the Channel (device) identifiers for each device to the Named User "john_doe_123," and push to the Named User. Notifications will then fan out to each associated device. ## Named User listing or lookup {#getnameduser} Return a list of Named Users or look up a single Named User by `named_user_id`. [Jump to examples ↓](#getnameduser-examples) ### `GET /api/named_users` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): nu **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `id` | `string` | | The `named_user_id` you want to look up. When querying a `named_user_id`, the response contains a single `named_user` object. If you do not query a specific `named_user_id`, the response returns an array of `named_users`, in which each object represents an individual Named User. | **Responses** **`200`** Returns OK for success. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` **One of:** - **`named_user`** `object` <[Named User object]({{< ref "/developer/rest-api/ua/schemas/named-user/" >}}#nameduserresponsebody)> The response body for a Named User listing, including tags, channels and attributes associated with the Named User. - **`ok`** `boolean` **REQUIRED** Success. - **`named_users`** `array` <[Named User object]({{< ref "/developer/rest-api/ua/schemas/named-user/" >}}#nameduserresponsebody)> - **`next_page`** `string` There might be more than one page of results for this listing. Follow this URL if it is present to the next page of results. Format: `url` Example: `https://go.urbanairship.com/api/named_users?start=john_doe` - **`ok`** `boolean` **REQUIRED** Success. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example Named User lookup* ```http GET /api/named_users/?id=user-456 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "named_user": { "named_user_id": "user-456", "created" : "2020-04-08T20:41:06", "last_modified" : "2020-05-01T18:00:27", "tags": { "my_fav_tag_group": [ "tag1", "tag2" ] }, "subscription_lists": [ { "list_ids": ["example_listId-1", "example_listId-5"], "scope": "web" }, { "list_ids": ["example_listId-2", "example_listId-3"], "scope": "app" }, { "list_ids": ["example_listId-2"], "scope": "web" }, { "list_ids": ["example_listId-3"], "scope": "email" }, { "list_ids": ["example_listId-4"], "scope": "sms" } ], "attributes": { "item_purchased": "Fur removal tool", "cats_name": "Sammy", "pets_age": 12 }, "user_attributes": { "ua_country": "US", "ua_language": "en", "ua_tz": "America/Los_Angeles" }, "channels": [ { "channel_id": "dceafd02-b852-4305-83df-98b65fa40dd4", "device_type": "ios", "installed": true, "opt_in": true, "push_address": "FFFF", "created": "2020-04-08T20:41:06", "last_registration": "2020-05-01T18:00:27", "tags": [ "meow" ] } ] } } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); NamedUserListingRequest request = NamedUserListingRequest.newRequest("user-456"); Response response = client.execute(request); NamedUserView namedUser = response.getBody().get().getNamedUserView().get(); // The Named User ID String namedUserId = namedUser.getNamedUserId(); // Map of tag groups and the associated sets of tags ImmutableMap> namedUserTags = namedUser.getNamedUserTags(); // All channel objects associated with the Named User ImmutableSet channelViews = namedUser.getChannelViews(); ``` ```python from urbanairship import ( BasicAuthClient, NamedUser ) client = BasicAuthClient( key='', secret='' ) named_user = NamedUser(airship=client, named_user_id='user-456') response = named_user.lookup() print(response) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') named_user = UA::NamedUser.new(client: airship) named_user.named_user_id = 'user-456' user = named_user.lookup ``` *Example Named User listing* ```http GET /api/named_users HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Data-Attribute: named_users Link: ; rel=next Content-Type: application/vnd.urbanairship+json; version=3 { "next_page": "https://go.urbanairship.com/api/named_users?start=user-1234", "named_users": [ { "named_user_id": "user-id-1234", "created" : "2020-04-08T20:41:06", "last_modified" : "2020-05-01T18:00:27", "tags": { "my_fav_tag_group": ["tag1", "tag2"] }, "subscription_lists": [ { "list_ids": ["example_listId-1", "example_listId-5"], "scope": "web" }, { "list_ids": ["example_listId-2", "example_listId-3"], "scope": "app" }, { "list_ids": ["example_listId-2"], "scope": "web" }, { "list_ids": ["example_listId-3"], "scope": "email" } ], "attributes":{ "item_purchased":"Fur removal tool", "cats_name":"fluffy butt", "pets_age":2 }, "user_attributes": { "ua_country": "US", "ua_language": "en", "ua_tz": "America/Los_Angeles" }, "channels": [ { "channel_id": "dceafd02-b852-4305-83df-98b65fa40dd5", "device_type": "ios", "installed": true, "opt_in": true, "push_address": "FFFF", "created": "2020-04-08T20:41:06", "last_registration": "2020-05-01T18:00:27", "alias": "xxxx", "tags": ["asdf"], "ios": { "badge": 0, "quiettime": { "start": "22:00", "end": "06:00" }, "tz": "America/Los_Angeles" } } ] } ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); NamedUserListingRequest request = NamedUserListingRequest.newRequest(); Response response = client.execute(request); ImmutableList namedUsers = response.getBody().get().getNamedUserViews().get(); ``` ```python from urbanairship import ( BasicAuthClient, NamedUserList ) client = BasicAuthClient( key='', secret='' ) named_user_list = NamedUserList(airship=client) for n in named_user_list: print(n.named_user_id) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') named_user_list = UA::NamedUserList.new(client: airship) named_user_list.each do |named_user| puts(named_user) end ``` --- ## Named User update {#updatenameduser} Create or update a Named User by associating/disassociating channels and adding/removing tags and attributes in a single request. [Jump to examples ↓](#updatenameduser-examples) ### `POST /api/named_users/{named_user_id}` {{< warning >}} If a channel has an assigned Named User and you make an additional call to associate that same channel with a new Named User, the original Named User association will be removed and the new Named User and associated data will take its place. Additionally, all tags associated to the original Named User cannot be used to address this channel unless they are also associated with the new Named User. {{< /warning >}} {{< important >}} We support up to 1,000 tags per Named User. Adding more than 1,000 tags per Named User can cause latency and service interruptions. We strongly recommend removing unused tags whenever possible, and using Custom Events when appropriate. Please [contact Support](https://support.airship.com/) if you believe your use case requires more than 1,000 tags per Named User, and they will help you find an alternative. {{< /important >}} **Security:** - [basicAppAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAppAuth) - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): nu **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `named_user_id` | `string` | Required | A string value identifying the user, without leading or trailing whitespace. If this value contains reserved or special characters they must be URL encoded. | **Request body** **Content-Type:** `application/json` [Named User update payload]({{< ref "/developer/rest-api/ua/schemas/named-user/" >}}#nameduserupdate) **Responses** **`200`** Request was accepted. Response body: **Content-Type:** `application/json` - **`attribute_warnings`** `string` Warnings encountered when processing attributes for this Named User. - **`ok`** `boolean` **REQUIRED** Set to `true` when status code is `200`. - **`tag_warnings`** `string` Warnings encountered when processing tags for this Named User. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Create a Named User by associating an email and SMS channel and setting tags and attributes. * ```http POST /api/named_users/john_doe HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "associate": [ { "email_address": "john@example.com" }, { "channel_id": "f5346fa3-99f1-496d-be37-2895ef58f5a5", "device_type": "sms" } ], "tags": { "set": { "subscription_status": ["gold"], "favorites" : ["sports", "stocks"] } }, "attributes": [ { "action": "set", "key": "name", "value": "John" } ] } ``` ```python from urbanairship import ( BasicAuthClient, NamedUser ) client = BasicAuthClient( key='', secret='' ) associate = [ {"email_address": "john@example.com"}, {"channel_id": "f5346fa3-99f1-496d-be37-2895ef58f5a5", "device_type": "sms"} ] tags = { "set": { "subscription_status": ["gold"], "favorites" : ["sports", "stocks"] } } attributes = [ { "action": "set", "key": "name", "value": "John" } ] named_user = NamedUser( airship=client, named_user_id="john_doe" ) response = named_user.update( associate=associate, tags=tags, attributes=attributes ) ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); NamedUserUpdateChannel namedUserUpdateChannel = NamedUserUpdateChannel.newBuilder() .addChannel(NamedUserUpdateDeviceType.ANDROID_CHANNEL, "aa2ae18c-f4b0-48ac-a859-55f26d2a7439") .build(); Attribute lastName = Attribute.newBuilder() .setAction(AttributeAction.SET) .setKey("pseudo") .setValue("Pataki") .build(); NamedUserUpdatePayload namedUserUpdatePayload = NamedUserUpdatePayload.newBuilder() .addAttribute(lastName) .addTags("go", List.of("test1","test2")) .removeTags("go",List.of("test3","test4")) .addNamedUserUpdateChannel(namedUserUpdateChannel) .setAction(NamedUserUpdateChannelAction.ASSOCIATE) .build(); NamedUserUpdateRequest request = NamedUserUpdateRequest.newRequest("john", namedUserUpdatePayload); Response response = client.execute(request); ``` --- ## Named Users association {#associatenameduser} Associate a channel or email address with a Named User (`named_user_id`). If the `named_user_id` does not already exist, this operation will create it. If the `channel_id` or `email address` is already associated with the `named_user_id`, this operation will do nothing. [Jump to examples ↓](#associatenameduser-examples) ### `POST /api/named_users/associate` {{< warning >}} If a channel has an assigned Named User and you make an additional call to associate that same channel with a new Named User, the original Named User association will be removed and the new Named User and associated data will take its place. Additionally, all tags associated to the original Named User cannot be used to address this channel unless they are also associated with the new Named User. {{< /warning >}} **Security:** - [basicAppAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAppAuth) - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): nu **Request body** Named User association requires a `channel_id` or `email_address`. Do not provide both in the same request. You can associate up to 100 Channel IDs to a Named User. Channel creation is asynchronous, so when associating a newly created channel, both a Channel ID and a device type are required to prevent "channel does not exist" errors. **Content-Type:** `application/json` **One of:** - **`channel_id`** `string` **REQUIRED** The Channel ID you want to associate with a Named User. Format: `uuid` Example: `9c36e8c7-5a73-47c0-9716-99fd3d4197d5` - **`device_type`** `string` The device type of the channel. Possible values: `ios`, `android`, `amazon`, `web`, `open`, `email`, `sms` - **`named_user_id`** `string` **REQUIRED** A string value identifying the user, without leading or trailing whitespace. Min length: 1, Max length: 128 Example: `john_doe` - **`email_address`** `string` **REQUIRED** The email address you want to associate with a Named User. Format: `email` Example: `user@example.com` - **`named_user_id`** `string` **REQUIRED** The existing Named User ID Min length: 1, Max length: 128 Example: `john_doe` **Responses** **`200`** The request was accepted but is not guaranteed to be successfully processed. If the Named User has more than 1,000 channels associated with it, the request will be ignored. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example associate an iOS channel with a Named User* ```http POST /api/named_users/associate HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "channel_id": "df6a6b50-9843-0304-d5a5-743f246a4946", "device_type": "ios", "named_user_id": "user-id-1234" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); NamedUserRequest request = NamedUserRequest.newAssociationRequest() .setChannel("df6a6b50-9843-0304-d5a5-743f246a4946", ChannelType.IOS) .setNamedUserId("user-id-1234"); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, NamedUser ) client = BasicAuthClient( key='', secret='' ) named_user = NamedUser(airship=client, named_user_id='user-id-1234') response = named_user.associate(channel_id='df6a6b50-9843-0304-d5a5-743f246a4946', device_type='ios') ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') named_user = UA::NamedUser.new(client: airship) named_user.named_user_id = 'user-id-1234' named_user.associate(channel_id: 'df6a6b50-9843-0304-d5a5-743f246a4946', device_type: 'ios') ``` *Example associate a web channel with Named User (do not declare device type)* ```http POST /api/named_users/associate HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "channel_id": "wf6a6b50-9843-0304-d5a5-743f246a4946", "named_user_id": "user-id-1234" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); NamedUserRequest request = NamedUserRequest.newAssociationRequest() .setChannel("wf6a6b50-9843-0304-d5a5-743f246a4946", ChannelType.WEB) .setNamedUserId("user-id-1234"); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, NamedUser ) client = BasicAuthClient( key='', secret='' ) named_user = NamedUser(airship=client, named_user_id='user-id-1234') response = named_user.associate(channel_id='wf6a6b50-9843-0304-d5a5-743f246a4946') ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') named_user = UA::NamedUser.new(client: airship) named_user.named_user_id = 'user-id-1234' named_user.associate(channel_id: 'wf6a6b50-9843-0304-d5a5-743f246a4946') ``` *Example associate an email channel with Named User* ```http POST /api/named_users/associate HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "email_address": "monopoly.man@example.com", "named_user_id": "user-id-1234" } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```python from urbanairship import ( BasicAuthClient, NamedUser ) client = BasicAuthClient( key='', secret='' ) named_user = NamedUser(airship=client, named_user_id='user-id-1234') response = named_user.email_associate(email_address='monopoly.man@example.com') ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); NamedUserRequest request = NamedUserRequest.newAssociationRequest() .setChannel("em6a6b50-9843-0304-d5a5-743f246a4946", ChannelType.EMAIL) .setNamedUserId("user-id-1234"); Response response = client.execute(request); ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') named_user = UA::NamedUser.new(client: airship) named_user.named_user_id = 'user-id-1234' named_user.associate(channel_id: 'em6a6b50-9843-0304-d5a5-743f246a4946') ``` --- ## Named Users disassociation {#disassociatednameduser} Disassociate a channel or an email address from a `named_user_id`. [Jump to examples ↓](#disassociatednameduser-examples) ### `POST /api/named_users/disassociate` **Security:** - [basicAppAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAppAuth) - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): nu **Request body** **Content-Type:** `application/json` **One of:** - **`channel_id`** `string` **REQUIRED** The Channel ID you want to disassociate from a Named User. Format: `uuid` Example: `9c36e8c7-5a73-47c0-9716-99fd3d4197d5` - **`device_type`** `string` The device type of the channel. Possible values: `ios`, `android`, `amazon`, `web`, `email`, `sms`, `open` - **`named_user_id`** `string` The existing Named User ID. Min length: 1, Max length: 128 Example: `john_doe` - **`email_address`** `string` **REQUIRED** The email address you want to disassociate from a Named User. Format: `email` Example: `user@example.com` - **`named_user_id`** `string` A string value identifying the new user with no leading or trailing whitespace. If the `named_user_id` does not already exist, this operation will create a new Named User and associate the `channel_id` with it. Min length: 1, Max length: 128 Example: `john_doe` **Responses** **`200`** The request was accepted but is not guaranteed to be successfully processed. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/named_users/disassociate HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "channel_id": "df6a6b50-9843-0304-d5a5-743f246a4946", "device_type": "ios", "named_user_id": "user-id-1234" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); NamedUserRequest request = NamedUserRequest.newDisassociationRequest() .setChannel("df6a6b50-9843-0304-d5a5-743f246a4946", ChannelType.IOS); Response response = client.execute(request); ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') named_user = UA::NamedUser.new(client: airship) named_user.disassociate(channel_id: 'df6a6b50-9843-0304-d5a5-743f246a4946', device_type: 'ios') ``` ```python from urbanairship import ( BasicAuthClient, NamedUser ) client = BasicAuthClient( key='', secret='' ) named_user = NamedUser(airship=client, named_user_id='user-id-1234') response = named_user.disassociate(channel_id='df6a6b50-9843-0304-d5a5-743f246a4946', device_type='ios') ``` *Example disassociate an email channel from Named User* ```http POST /api/named_users/disassociate HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "email_address": "monopoly.man@example.com", "named_user_id": "user-id-1234" } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```python from urbanairship import ( BasicAuthClient, NamedUser ) client = BasicAuthClient( key='', secret='' ) named_user = NamedUser(airship=client, named_user_id='user-id-1234') response = named_user.email_disassociate(email_address='monopoly.man@example.com') ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); NamedUserRequest request = NamedUserRequest.newDisassociationRequest() .setChannel("em6a6b50-9843-0304-d5a5-743f246a4946", ChannelType.EMAIL) .setNamedUserId("user-id-1234"); Response response = client.execute(request); ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') named_user = UA::NamedUser.new(client: airship) named_user.disassociate(channel_id: 'em6a6b50-9843-0304-d5a5-743f246a4946') ``` --- ## Named Users tags {#modifynamedusertags} Add, remove, or set tags on a Named User. A single request body may contain add and/or remove objects or a single set field. At least one of the add, remove, or set objects must be present in a request. [Jump to examples ↓](#modifynamedusertags-examples) ### `POST /api/named_users/tags` {{< important >}} A tag must be < 128 characters. A request with one or more tags longer than 128 characters will return a 400 response. We support up to 1,000 tags per Named User. Adding more than 1,000 tags per Named User can cause latency and service interruptions. We strongly recommend removing unused tags whenever possible, and using Custom Events when appropriate. Please [contact Support](https://support.airship.com/) if you believe your use case requires more than 1,000 tags per Named User, and they will help you find an alternative. {{< /important >}} **Security:** - [basicAppAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAppAuth) - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): nu **Request body** **Content-Type:** `application/json` - **`add`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Add the list of tags to the Named User(s), but do not remove any. If the tags are already present, they are not modified. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`audience`** `object` **REQUIRED** The Named User(s) you want to associate/disassociate tags with. **OBJECT PROPERTIES** - **`named_user_id`** `array[string]` Min items: 1, Max items: 1000 - **`remove`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Remove the list of tags from the Named User(s), but do not remove any others. If the tags are not currently present, nothing happens. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`set`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Set these tags for the audience; any tags previously associated with the audience tags that are not in this current list are removed. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. **Responses** **`200`** If a tag request is partially valid, i.e., at least one tag group exists and is active, a 200 will be returned with a warning in the response about the tag groups that failed to update. The tag groups listed in the warning will be CSV-formatted. Response body: **Content-Type:** `application/json` - **`ok`** `boolean` **REQUIRED** Set to `true` when status code is `200`. - **`tag_warnings`** `string` Warnings encountered when processing tags for this Named User. **`400`** Parsing or validating the request failed. You will see this error if the same tag is present in both the add and remove fields. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/named_users/tags HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "named_user_id": [ "user-1", "user-2", "user-3" ] }, "add": { "crm": [ "tag1", "tag2", "tag3" ], "loyalty": [ "tag1", "tag4", "tag5" ] }, "remove": { "loyalty": [ "tag6", "tag7" ] } } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); NamedUserTagRequest request = NamedUserTagRequest.newRequest() .addNamedUsers("user-1", "user-2", "user-3") .addTags("crm", ImmutableSet.of("tag1", "tag2", "tag3")) .addTags("loyalty", ImmutableSet.of("tag1", "tag4", "tag5")) .removeTags("loyalty", ImmutableSet.of("tag6", "tag7")); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, NamedUser ) client = BasicAuthClient( key='', secret='' ) named_user = NamedUser(airship=client, named_user_id='user-1') resp1 = named_user.tag( group='loyalty', add=['tag2', 'tag3', 'tag4'], remove='tag1' ) resp2 = named_user.tag( group='crm', set=['tag5', 'tag6'] ) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') named_user_tags = UA::NamedUserTags.new(client: airship) named_user_ids = ['user-1', 'user-2', 'user-3'] named_user_tags.set_audience(user_ids: named_user_ids) named_user_tags.add(group_name: 'crm', tags: ['tag1', 'tag2', 'tag3']) named_user_tags.remove(group_name: 'loyalty', tags: ['tag6', 'tag7']) named_user_tags.send_request ``` --- ## Named Users uninstall {#uninstallnameduser} Disassociate and delete all channels associated with the named_user_id(s) and also delete the named_user_id(s). This call removes all channels associated with a Named User from Airship systems in compliance with data privacy laws. Uninstalling channels also removes accompanying analytic data (including Performance Analytics) from the system. See [Individual Data Privacy Rights Under Data Privacy Laws](/docs/guides/audience/privacy/individual-data-privacy/) for more information about data privacy law compliance. [Jump to examples ↓](#uninstallnameduser-examples) ### `POST /api/named_users/uninstall` {{< note >}} Channel uninstallation, like channel creation, is an asynchronous operation and may take some time to complete. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): nu **Request body** **Content-Type:** `application/json` - **`named_user_id`** `array[string]` **REQUIRED** Array of strings representing the named_user_id(s) you wish to be uninstalled. Must have between 1 to 100 items in the array with a 128 character/byte maximum per item. Min items: 1, Max items: 100 **Responses** **`200`** All channels have been deleted and disassociated from the Named User. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example delete all users and their associated channels* ```http POST /api/named_users/uninstall HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "named_user_id": ["user-id-1234","user-id-5678"] } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```python from urbanairship import ( BasicAuthClient, NamedUser ) client = BasicAuthClient( key='', secret='' ) response = NamedUser.uninstall( client=client, named_users=["user-id-1234", "user-id-5678"] ) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') named_user_uninstall = UA::NamedUserUninstaller.new(client: airship) named_user_uninstall.named_user_ids = ['user-id-1234'] named_user_uninstall.uninstall ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); NamedUserUninstallRequest namedUserUninstallRequest = NamedUserUninstallRequest .newUninstallRequest(ImmutableList.of("user-id-1234","user-id-5678")); Response response = client.execute(namedUserUninstallRequest); ``` --- ## Scoped Named User batch operations {#performnameduserscopedbatchoperations} Supports multiple operations on a Named User within a single request for a specified `scope`. The supported operation is `subscription_lists`. The behavior of each of these operations are the same as their individual request counterpart. [Jump to examples ↓](#performnameduserscopedbatchoperations-examples) ### `POST /api/named_users/scoped/{named_user_id}` {{< note >}} If you are using a single-channel Preference Center created before October 10, 2022, that has not been [migrated to user-level](/docs/guides/messaging/features/preference-centers/#migrating-to-a-user-level-preference-center), use the [`/api/channels/subscription_lists` endpoint](/docs/developer/rest-api/ua/operations/channels/#modifychannelsubscriptions) to add or remove individual channels to/from your subscription list. {{< /note >}} {{< important >}} The path parameter `named_user_id` should be URL-encoded to ensure it is handled correctly. Requirements of `named_user_id` can be found [here](#operation-api-named_users-associate-post-associate-channel_id-with-named-user-named_user_id). {{< /important >}} **Security:** - [basicAppAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAppAuth) - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): nu **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `named_user_id` | `string` | Required | A string value identifying the user, without leading or trailing whitespace. If this value contains reserved or special characters they must be URL encoded. | **Request body** **Content-Type:** `application/json` - **`scoped`** `array` <[Named User scoped batch item]({{< ref "/developer/rest-api/ua/schemas/subscription-lists/" >}}#scopedbatchitem)> An array of scopes and subscription lists. **Responses** **`200`** The scoped Named User batch operations succeeded. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example scoped Named User batch operations * ```http POST /api/named_users/scoped/b8f9b663-0a3b-cf45-587a-be880946e881 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "scoped": [ { "scope": ["app"], "subscription_lists": { "subscribe": ["stickers", "gifs"], "unsubscribe": ["cookies"] } }, { "scope": ["web"], "subscription_lists": { "subscribe": ["daily_snacks", "brunch"], "unsubscribe": ["promotions"] } } ] } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); Set scopeTypes1 = new HashSet<>(Arrays.asList(NamedUserScopeType.APP)); Set subscribeLists1 = new HashSet<>(Arrays.asList("stickers", "gifs")); Set unsubscribeLists1 = new HashSet<>(Arrays.asList("cookies")); Set scopeTypes2 = new HashSet<>(Arrays.asList(NamedUserScopeType.WEB)); Set subscribeLists2 = new HashSet<>(Arrays.asList("daily_snacks", "brunch")); Set unsubscribeLists2 = new HashSet<>(Arrays.asList("promotions")); NamedUserScope namedUserScope1 = NamedUserScope.newBuilder() .setScopes(scopeTypes1) .setSubscribeLists(subscribeLists1) .setUnsubscribeLists(unsubscribeLists1) .build(); NamedUserScope namedUserScope2 = NamedUserScope.newBuilder() .setScopes(scopeTypes2) .setSubscribeLists(subscribeLists2) .setUnsubscribeLists(unsubscribeLists2) .build(); NamedUserScopedPayload namedUserScopedPayload = NamedUserScopedPayload.newBuilder() .addNamedUserScope(namedUserScope1) .addNamedUserScope(namedUserScope2) .build(); NamedUserScopedRequest request = NamedUserScopedRequest.newRequest("named_user_id", namedUserScopedPayload); Response response = client.execute(request); ``` --- ## Set or remove attributes on Named Users {#modifynameduserattributes} Set or remove attributes on a Named User. A single request body may contain a `set` or `remove` field, or both, or a single `set` field. If both `set` and `remove` fields are present and the intersection of the attributes in these fields is not empty, then a `400` will be returned. If an attribute request is partially valid, i.e., at least one attribute exists, Airship returns a `200` with a warning about the attributes that failed to update. The attributes listed in the `warnings` string will be in CSV format. [Jump to examples ↓](#modifynameduserattributes-examples) ### `POST /api/named_users/{named_user_id}/attributes` {{< note >}} Airship returns a `200` with a warning if you attempt to set attributes on a Named User that does not exist. {{< /note >}} {{< tip >}} If you wish to set attributes on multiple Named Users at once, we recommend using [/api/channels/attributes](/docs/developer/rest-api/ua/operations/channels/#modifychannelattributes) which supports an `audience` object in the request body. {{< /tip >}} **Security:** - [basicAppAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAppAuth) - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): nu **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `named_user_id` | `string` | Required | The Named User you are setting the attributes for. | **Request body** **Content-Type:** `application/json` Type: `array` **Responses** **`200`** Success. If an attribute request is partially valid, i.e., at least one attribute exists, Airship returns a `200` with a warning string containing a CSV list of attributes that failed to update. Airship also returns a `200` with a warning if you attempt to set attributes on a `named_user`, even if the `named_user` does not exist. Response body: **Content-Type:** `application/json` - **`ok`** `boolean` Set to `true` when status code is `200`. - **`warnings`** `string` Warnings encountered when updating Named User attributes. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/named_users/my_named_user/attributes HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "attributes": [ { "action": "set", "key": "firstName", "value": "Gyuri", "timestamp": "2020-09-19 12:00:00" }, { "action": "remove", "key": "birthDate", "timestamp": "2020-09-19 12:00:00" }, { "action": "set", "key": "lastName", "value": "Pataki", "timestamp": "2020-09-19 12:00:00" } ] } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```python from urbanairship import ( BasicAuthClient, Attribute, ModifyAttributes ) client = BasicAuthClient( key='', secret='' ) set_major_league = Attribute( action="set", key="major_league", value="sf_giants") remove_minor_league = Attribute( action="remove", key="minor_league") set_position = Attribute( action="set", key="position", value="LF") modifications = ModifyAttributes( airship=client, attributes=[set_major_league, remove_minor_league, set_position], named_user="my_named_user" ) modifications.send() ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); Attribute firstName = Attribute.newBuilder() .setAction(AttributeAction.SET) .setKey("firstName") .setValue("Gyuri") .setTimeStamp(DateTime.parse("2020-09-19T12:00:00Z")) .build(); Attribute birthDate = Attribute.newBuilder() .setAction(AttributeAction.REMOVE) .setKey("birthDate") .setTimeStamp(DateTime.parse("2020-09-19T12:00:00Z")) .build(); Attribute lastName = Attribute.newBuilder() .setAction(AttributeAction.SET) .setKey("lastName") .setValue("Pataki") .setTimeStamp(DateTime.parse("2020-09-19T12:00:00Z")) .build(); NamedUserAttributePayload payload = NamedUserAttributePayload.newBuilder() .addAttribute(firstName) .addAttribute(birthDate) .addAttribute(lastName) .build(); NamedUserAttributeRequest request = NamedUserAttributeRequest.newRequest("my_named_user", payload); Response response = client.execute(request); ``` --- # OAuth > Request an OAuth 2.0 token using Basic Auth or an assertion. ## Request token {#requestoauthtoken} Request an OAuth access token with Basic Auth or an assertion. When making a request with an assertion, do not provide the Basic Auth header. See also [OAuth 2.0](/docs/guides/getting-started/developers/api-security/#oauth-20) in the *Airship API Security* documentation. Use `oauth2.asnapius.com` for Airship's North American cloud site and `oauth2.asnapieu.com` for Airship's European cloud site when requesting an OAuth token. [Jump to examples ↓](#requestoauthtoken-examples) ### `POST /token` {{< note >}} When using the OAuth token for Airship API endpoints, make sure your requests are using the appropriate [domain in the base URL](/docs/developer/rest-api/ua/introduction/#servers). This example uses the OAuth token to list channels on Airship's North American cloud site: {{< highlight "bash" >}} curl --location 'https://api.asnapius.com/api/channels/' \ --header 'Accept: application/vnd.urbanairship+json; version=3;' \ --header 'Authorization: Bearer {OAUTH_ACCESS_TOKEN}' {{< /highlight >}} {{< /note >}} **Security:** - [basicOauth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicOauth) **Request headers:** | Name | Type | Required | Description | |------|------|----------|-------------| | `Content-Type` | `string` | Required | The request must have a `Content-Type` of `application/x-www-form-urlencoded`. | **Request body** **Content-Type:** `application/x-www-form-urlencoded` **One of:** - **`grant_type`** `string` **REQUIRED** Possible values: `client_credentials` - **`ipaddr`** `string` A list of CIDR representations of valid IP addresses to which the issued token is restricted. IP addresses can be sent as a URL-encoded, space-delimited list (example: `ipaddr=24.20.40.0%2F24%202001%3A4860%3A4860%3A%3A8888%2F32`) or as a list as expected in a query parameter form (example: `ipaddr=24.20.40.0/24&ipaddr=2001:4860:4860::8888/32`). - **`scope`** `string` <[OAuth Scope]({{< ref "/developer/rest-api/ua/schemas/oauth/" >}}#oauthscope)> A list of scopes to which the issued token will be entitled. Scopes can be sent as URL-encoded, space-delimited list (example: `scope=chn%20nu`) or as a list as expected in a query parameter form (example: `scope=chn&scope=nu`). The value of the scope parameter is a list of space-delimited, case-sensitive strings. If multiple scopes are specified, their order does not matter. Each string adds an additional access range to the requested scope. For more information about scope values, see [OAuth token scopes](/docs/developer/rest-api/ua/api-auth-reference/#oauth-token-scopes) in the *Airship API Authorization Reference* documentation. * `att`: Attachments * `chn`: Channels * `tpl`: Content * `evt`: Events * `lst`: Lists * `nu`: Named Users * `pln`: Pipelines * `psh`: Push * `rpt`: Reports * `sch`: Schedules Possible values: `att`, `chn`, `tpl`, `evt`, `lst`, `nu`, `pln`, `psh`, `rpt`, `sch` - **`sub`** `object` <[Subject]({{< ref "/developer/rest-api/ua/schemas/oauth/" >}}#subject)> **REQUIRED** A space-delimited set of identifiers for which subjects a token is allowed. An `app` subject is required. Example: `app:`. A space-delimited set of identifiers for which subjects a token is allowed. Example: `app:` * `app`: May operate on the given app - **`assertion`** `object` <[Assertion JWT]({{< ref "/developer/rest-api/ua/schemas/oauth/" >}}#assertionjwt)> **REQUIRED** An encoded JWT that contains the required headers and claims and is signed with the client credentials' private key. A JSON Web Token (JWT) used for authorization in [OAuth token requests](/docs/developer/rest-api/ua/operations/oauth/#requestoauthtoken). The JWT must be signed with the private key corresponding to the `client_id` in the `kid` header using the ES384 algorithm. - **`grant_type`** `string` **REQUIRED** Possible values: `client_credentials` **Responses** **`200`** Returned on token request success. Response headers: | Name | Type | Description | |------|------|-------------| | `Cache-Control` | `string` | Possible values: `no-store` | | `Content-Type` | `string` | Possible values: `application/json` | | `Pragma` | `string` | Possible values: `no-cache` | Response body: **Content-Type:** `application/json` - **`access_token`** `string` The issued token that can be used for all endpoints as allowed by set scopes. - **`expires_in`** `integer` The number of seconds from the time the token is generated until it expires. - **`scope`** `string` <[OAuth Scope]({{< ref "/developer/rest-api/ua/schemas/oauth/" >}}#oauthscope)> A space-delimited list of scopes of the issued token. There may be undocumented scopes in this list. The value of the scope parameter is a list of space-delimited, case-sensitive strings. If multiple scopes are specified, their order does not matter. Each string adds an additional access range to the requested scope. For more information about scope values, see [OAuth token scopes](/docs/developer/rest-api/ua/api-auth-reference/#oauth-token-scopes) in the *Airship API Authorization Reference* documentation. * `att`: Attachments * `chn`: Channels * `tpl`: Content * `evt`: Events * `lst`: Lists * `nu`: Named Users * `pln`: Pipelines * `psh`: Push * `rpt`: Reports * `sch`: Schedules Possible values: `att`, `chn`, `tpl`, `evt`, `lst`, `nu`, `pln`, `psh`, `rpt`, `sch` - **`token_type`** `string` The type of issued token. Possible values: `Bearer` **`400`** Token not generated. Response body: **Content-Type:** `application/json` - **`error`** `string` **REQUIRED** Error code. Possible values: `invalid_scope`, `invalid_request`, `invalid_grant`, `unauthorized_client`, `unsupported_grant_type`, `invalid_client` - **`error_description`** `string` A plain-text description of the error. **`401`** Unauthorized. Response headers: | Name | Type | Description | |------|------|-------------| | `WWW-Authenticate` | `string` | The HTTP authentication methods that can be used to request an access token. | Response body: **Content-Type:** `application/json` - **`error`** `string` **REQUIRED** Error code. Possible values: `invalid_client` - **`error_description`** `string` A plain-text description of the error. **`406`** Not acceptable. Response body: **Content-Type:** `application/json` - **`error`** `string` **REQUIRED** Error code. Possible values: `invalid_request` - **`error_description`** `string` A plain-text description of the error. **Examples** *Example request token with Basic Auth* ```http POST /token HTTP/1.1 Host: oauth2.asnapius.com Content-Type: application/x-www-form-urlencoded Accept: application/json Authorization: Basic grant_type=client_credentials&sub=app:YOUR_APP_KEY&scope=chn&scope=nu&ipaddr=24.20.40.0/24&ipaddr=2001:4860:4860::8888/32 ``` ```http HTTP/1.1 200 OK Content-Type: application/json Cache-Control: no-store Pragma: no-cache { "access_token": "", "token_type": "Bearer", "scope": "chn nu", "expires_in": 3600 } ``` ```java OAuthCredentials oAuthCredentials = OAuthCredentials.newBuilder("") .setClientSecret("") .setSub("") .setScopes(Arrays.asList("","","<...>")) .setIpAddresses(Arrays.asList("","",<...>)) .build(); UrbanAirshipClient oAuthClient = UrbanAirshipClient.newBuilder() .setKey("yourAppKey") .setOAuthCredentials(oAuthCredentials) .build(); ``` *Example request token with assertion* ```http POST /token HTTP/1.1 Host: oauth2.asnapius.com Content-Type: application/x-www-form-urlencoded Accept: application/json grant_type=client_credentials&assertion= ``` ```http HTTP/1.1 200 OK Content-Type: application/json Cache-Control: no-store Pragma: no-cache { "access_token": "", "token_type": "Bearer", "scope": "chn nu", "expires_in": 3600 } ``` ```java OAuthCredentials oAuthCredentials = OAuthCredentials.newBuilder("") .setAssertionJWT("") .build(); UrbanAirshipClient oAuthClient = UrbanAirshipClient.newBuilder() .setKey("") .setOAuthCredentials(oAuthCredentials) .build(); ``` ```python # The python OAuth client handles JWT creation # and token refresh automatically. # Once instantiated, this can be used as any other Airship client. airship_client = OAuthClient( client_id="", private_key="", key="", scope=["",], id_addr=["",], timeout="", retries="" ) ``` ```ruby require 'urbanairship' UA = Urbanairship app_key = '' oauth = UA::Oauth.new( client_id: '', key: app_key, assertion_private_key: '', scopes: ['psh', 'chn'], # Optional ip_addresses: ['23.74.131.15/22'], # Optional oauth_server: 'api.asnapieu.com' # Optional ) airship = UA::Client.new(key: app_key, oauth: oauth) ``` --- ## Verify public key {#getkeyverification} Retrieve the public key of a key ID. Use `oauth2.asnapius.com` for Airship's North American cloud site and `oauth2.asnapieu.com` for Airship's European cloud site when verifying an OAuth public key. [Jump to examples ↓](#getkeyverification-examples) ### `GET /verify/public_key/{kid}` **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `kid` | `string` | Required | The private key ID used to sign the token. Example: `8817e96` | **Responses** **`200`** Returned on success with the public key for the given `kid`. Response headers: | Name | Type | Description | |------|------|-------------| | `Cache-Control` | `string` | The response contains a `Cache-Control` header which must be respected. | Response body: **Content-Type:** `application/x-pem-file` Type: `string` **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/json` Type: `object` **Examples** *Example verify public key* ```http GET /verify/public_key/8817e96 HTTP/1.1 Host: oauth2.asnapius.com Accept: text/plain ``` ```http HTTP/1.1 200 OK Content-Type: application/x-pem-file Cache-Control: max-age=600, must-revalidate -----BEGIN PUBLIC KEY----- MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE7tcTz03ypC7PSPa73Cbgl7AbDDo+92eH DWgjAi6vt1gmlHE35e+GhpcwbywBByOiooY+5bvfUHkc0aKy4R8VbBK0rYwlp8B+ fxyDr9Ye/oiUewMwwlp0z5AMPjgBUIKS -----END PUBLIC KEY----- ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); PublicKeyVerificationRequest request = PublicKeyVerificationRequest.newRequest(""); Response response = client.execute(request); ``` ```ruby require 'urbanairship' UA = Urbanairship app_key = '' oauth = UA::Oauth.new( client_id: '', key: app_key, assertion_private_key: '', scopes: ['psh', 'chn'], # Optional ip_addresses: ['23.74.131.15/22'], # Optional oauth_server: 'api.asnapieu.com' # Optional ) public_key = oauth.verify_public_key('') ``` --- # Open Channels > Open Channels are custom communication channels that you can configure for messaging, using the same segmentation and scheduling tools available on natively-supported platforms (iOS, Android, etc.). With Open Channels, you define a new open platform, e.g., SMS, Slack, Acme™ Smart Toasters, and register the new platform with Airship. If you are sending through the [Push API](/developer/rest-api/ua/operations/push/), platform overrides for open platforms are covered in [Open Channel Overrides](/developer/rest-api/ua/schemas/platform-overrides/#openchanneloverrideobject). For open channel lookup, use the [Channel Lookup endpoint](/developer/rest-api/ua/operations/channels/#getchannel). ## Open channel tags {#modifyopenchanneltags} Manipulate a single open channel’s tags. Open channels are identified by `address`, not by their `channel_id`. [Jump to examples ↓](#modifyopenchanneltags-examples) ### `POST /api/channels/open/tags` {{< important >}} A tag must be < 128 characters. A request with one or more tags longer than 128 characters will return a 400 response. We support up to 1,000 tags per channel. Adding more than 1,000 tags per channel can cause latency and service interruptions. We strongly recommend removing unused tags whenever possible, and using Custom Events when appropriate. Please [contact Support](https://support.airship.com/) if you believe your use case requires more than 1,000 tags per channel, and they will help you find an alternative. {{< /important >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** **Content-Type:** `application/json` - **`add`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Adds the specified tags to the channel. Tags that are already present are not modified/removed as a result of this operation. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`audience`** `object` **REQUIRED** The request body containing an address and `open_platform_name`. **OBJECT PROPERTIES** - **`address`** `string` **REQUIRED** Where notifications sent to this `channel_id` will be sent. Examples: email address, phone number. If missing, `channel_id` must be present. The `address` is one-to-one with the `channel_id`. New addresses on existing channels will overwrite old associations. Example: `new_email@example.com` - **`open_platform_name`** `string` **REQUIRED** An alphanumeric string that must be the name of a pre-created open platform object. Min length: 1, Max length: 128 Example: `twitter` - **`remove`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Removes the specified tags from the channel. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`set`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Assigns a list of tags exactly. Any previously set tags that are not in this current list will be removed. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. **Responses** **`200`** Returns OK for success. If a tag request is partially valid, i.e., at least one tag group exists and is active, a 200 is returned with a warning in the response about the tag groups that failed to update. The tag groups listed in the warning will be CSV-formatted. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/open/tags HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "address": "Number Four", "open_platform_name": "cylon" }, "add": { "my_fav_tag_group1": ["tag1", "tag2", "tag3"], "my_fav_tag_group2": ["tag1", "tag2", "tag3"], "my_fav_tag_group3": ["tag1", "tag2", "tag3"] } } ``` ```http HTTP/1.1 200 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok":true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); OpenChannelTagRequest openChannelTagRequest = OpenChannelTagRequest.newRequest() .addOpenChannel("Number Four","cyclon") .addTags("CRM_Delux", Set.of("tag1","tag2")) .removeTags("CRM_Delux", Set.of("tag3","tag4")); Response response = client.execute(openChannelTagRequest); ``` ```python from urbanairship import ( BasicAuthClient, OpenChannel ) client = BasicAuthClient( key='', secret='' ) channel = OpenChannel(airship=client) channel.address = 'Number Four' channel.open_platform = 'cylon' channel.tags = ['tag1', 'tag2', 'tag3'] response = channel.update() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') open_channel = UA::OpenChannel.new(client: airship) open_channel.opt_in = true open_channel.address = 'Number Four' open_channel.open_platform = 'cylon' open_channel.channel_id = 'df6a6b50-9843-0304-d5a5-743f246a4946' open_channel.tags = ['tag1', 'tag2', 'tag3'] open_channel.update(set_tags: true) ``` --- ## Register new or update channel {#createorupdateopenchannel} Create a new open channel or update an existing open channel. [Jump to examples ↓](#createorupdateopenchannel-examples) ### `POST /api/channels/open` {{< note >}} A 200 status will be returned if an existing channel was found for the specified `open_platform_name` and address. Otherwise, a new channel will be created and a 200 status will be returned. {{< /note >}} {{< important >}} The master secret is required to update an open channel, otherwise a 401 Unauthorized response is returned. {{< /important >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** An open channel object. **Content-Type:** `application/json` - **`channel`** `object` **REQUIRED** Properties of the open channel object. **OBJECT PROPERTIES** - **`address`** `string` **REQUIRED** Where notifications sent to this `channel_id` will be sent. Examples: email address, phone number. If missing, `channel_id` must be present. The `address` is one-to-one with the `channel_id`. New addresses on existing channels will overwrite old associations. Example: `+1 5558675309` - **`locale_country`** `string` The two-letter country locale short code. Will set the `ua_locale_country` tag group to the specified value. Example: `US` - **`locale_language`** `string` The two-letter language locale short code. Will set the `ua_locale_language` tag group to the specified value. - **`open`** `object` **REQUIRED** Open channel-specific properties. **OBJECT PROPERTIES** - **`identifiers`** `object` Optional object with string-to-string key:value pairs that represent non-segmentable identifiers for the channel in your delivery systems. Delivered as part of webhook payloads. If present, the value will overwrite (not union with) existing identifier records. Max items: 100 Example: `[object Object]` - **`open_platform_name`** `string` **REQUIRED** The name of the open platform to which you are registering this channel. Example: `slack` - **`opt_in`** `boolean` **REQUIRED** If false, no payloads will be delivered for the channel. - **`tags`** `array[string]` A list of strings used for audience targeting. When used for this endpoint, operates like the `tags { set {}}` operation; specified tags are applied, and all other tags are removed. Min items: 1, Max items: 1000 Example: `one_tag,two_tag,red_tag,blue_tag` - **`timezone`** `string` An IANA tzdata identifier for the time zone as a string, e.g., `"America/Los_Angeles"`. Will set the `timezone` tag group tag with the specified value. Example: `America/Los_Angeles` - **`type`** `string` **REQUIRED** Required string. Possible values: `open` **Responses** **`200`** Returned if the new channel is created successfully or if an existing channel was found for the specified open_platform_name and address. Response headers: | Name | Type | Description | |------|------|-------------| | `Location` | `string` | Used for later API calls for this channel. | Response body: **Content-Type:** `application/json` - **`channel_id`** `string` Identifies the new open channel or the open channel you successfully updated. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`ok`** `boolean` Success. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`429`** Too many requests hit the API too quickly. For example, if we are not ready to create a channel for this payload; e.g., it is rate limited. You should wait before retrying the channel creation. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/open HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "channel": { "type": "open", "opt_in": true, "address": "Number Four", "tags": [ "toaster", "caprica" ], "timezone": "America/Los_Angeles", "locale_country": "US", "locale_language": "en", "open": { "open_platform_name": "cylon", "identifiers": { "model": "4" } } } } ``` ```http HTTP/1.1 200 OK Location: https://go.urbanairship.com/api/channels/df6a6b50-9843-0304-d5a5-743f246a4946 Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "channel_id": "df6a6b50-9843-0304-d5a5-743f246a4946" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); OpenChannel openChannel = OpenChannel.newBuilder() .setOpenPlatformName("cylon") .setOldAddress("Number Four") .addIdentifier("model", "4") .build(); Channel channel = Channel.newBuilder() .setOpenChannel(openChannel) .setChannelType(ChannelType.OPEN) .setOptIn(true) .setAddress("Number Four") .setTags(true) .addTag("toaster") .setTimeZone("America/Los_Angeles") .setLocaleCountry("US") .setLocaleLanguage("en") .build(); OpenChannelPayload payload = new OpenChannelPayload(channel); OpenChannelRequest request = OpenChannelRequest.newRequest(payload); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, OpenChannel ) client = BasicAuthClient( key='', secret='' ) channel = OpenChannel(airship=client) channel.address = 'Number Four' channel.open_platform = 'cylon' channel.opt_in = True channel.tags = ['toaster', 'caprica'] channel.identifiers = {'model': '4'} response = channel.create() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') open_channel = UA::OpenChannel.new(client: airship) open_channel.opt_in = true open_channel.address = 'Number Four' open_channel.open_platform = 'cylon' open_channel.create() ``` --- ## Uninstall open channels {#uninstallopenchannels} Uninstall a channel needing to know its Channel ID. You cannot send notifications to, or get channel information for, an uninstalled channel. [Jump to examples ↓](#uninstallopenchannels-examples) ### `POST /api/channels/open/uninstall` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** An `address` and the `open_platform_name` you want to uninstall the address from. **Content-Type:** `application/json` - **`address`** `string` **REQUIRED** Where notifications sent to this `channel_id` will be sent. Examples: email address, phone number. If missing, `channel_id` must be present. The `address` is one-to-one with the `channel_id`. New addresses on existing channels will overwrite old associations. Example: `new_email@example.com` - **`open_platform_name`** `string` **REQUIRED** An alphanumeric string that must be the name of a pre-created open platform object. Min length: 1, Max length: 128 Example: `twitter` **Responses** **`202`** The request has been accepted for processing. Response body: **Content-Type:** `application/json` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/open/uninstall HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "address": "Number Four", "open_platform_name": "cylon" } ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); OpenChannelUninstallRequest openChannelUninstallRequest = OpenChannelUninstallRequest.newRequest("Number Four","cyclon"); Response response = client.execute(openChannelUninstallRequest); ``` ```python from urbanairship import ( BasicAuthClient, OpenChannel ) client = BasicAuthClient( key='', secret='' ) channel = OpenChannel(airship=client) channel.address = 'Number Four' channel.open_platform = 'cylon' response = channel.uninstall() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') cu = UA::OpenChannelUninstall.new(client: airship) cu.uninstall(address: 'Number Four', open_platform: 'cylon') ``` --- # Personalization > Use the `/templates` API to create templates and push templatized notifications. {{< note >}} The Personalization (`/templates`) API is deprecated. Instead, [create templates in the Airship dashboard](/docs/guides/personalization/content/templates/) or use the [Content API](/docs/developer/rest-api/ua/operations/content/), and send using the [Bulk sending](/docs/developer/rest-api/ua/operations/bulk-sending/) or [Automation](/docs/developer/rest-api/ua/operations/automation/) APIs. {{< /note >}} ## Create template {#createtemplate} Create a new template. [Jump to examples ↓](#createtemplate-examples) ### `POST /api/templates` {{< note >}} The Personalization (`/templates`) API is deprecated. Instead, [create templates in the Airship dashboard](/docs/guides/personalization/content/templates/) or use the [Content API](/docs/developer/rest-api/ua/operations/content/), and send using the [Bulk sending](/docs/developer/rest-api/ua/operations/bulk-sending/) or [Automation](/docs/developer/rest-api/ua/operations/automation/) APIs. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) **Request body** A single template object. **Content-Type:** `application/json` [Template object]({{< ref "/developer/rest-api/ua/schemas/personalization-template-objects/" >}}#templateobject) **Responses** **`201`** The template was created. Response headers: | Name | Type | Description | |------|------|-------------| | `Location` | `string` | The URI for the template, used for later updates or sends. | Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` **REQUIRED** If `true`, the operation completed successfully and returns an expected response. - **`operation_id`** `string` A unique string identifying the operation, useful for reporting and troubleshooting. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`template_id`** `string` A unique string identifying the template, used to call the template for pushing and other operations. Format: `uuid` Example: `0f7704e9-5dc0-4f7d-9964-e89055701b0a` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/templates HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "name": "Welcome Message", "description": "Our welcome message", "variables": [ { "key": "TITLE", "name": "Title", "description": "e.g., Mr, Ms, Dr, etc.", "default_value": "" }, { "key": "FIRST_NAME", "name": "First Name", "description": "Given name", "default_value": null }, { "key": "LAST_NAME", "name": "Last Name", "description": "Family name", "default_value": null } ], "push": { "notification": { "alert": "Hello {{FIRST_NAME}}, this is your welcome message!" } } } ``` ```http HTTP/1.1 201 Created Location: https://go.urbanairship.com/api/templates/ef34a8d9-0ad7-491c-86b0-aea74da15161 Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "operation_id" : "9ce808c8-7176-45dc-b79e-44aa74249a5a", "template_id": "ef34a8d9-0ad7-491c-86b0-aea74da15161" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); TemplateVariable titleVariable = TemplateVariable.newBuilder() .setKey("TITLE") .setName("Title") .setDescription("e.g., Mr, Ms, Dr, etc.") .setDefaultValue("") .build(); TemplateVariable firstNameVariable = TemplateVariable.newBuilder() .setKey("FIRST_NAME") .setName("First Name") .setDescription("Given name") .setDefaultValue(null) .build(); TemplateVariable lastNameVariable = TemplateVariable.newBuilder() .setKey("LAST_NAME") .setName("Last Name") .setDescription("Family name") .setDefaultValue("") .build(); PartialPushPayload partialPushPayload = PartialPushPayload.newBuilder() .setNotification(Notification.newBuilder() .setAlert("Hello {{TITLE}} {{FIRST_NAME}} {{LAST_NAME}}, this is your welcome message!") .build() ) .build(); TemplateRequest request = TemplateRequest.newRequest() .setName("Welcome Message") .setDescription("Our welcome message") .addVariable(titleVariable) .addVariable(firstNameVariable) .addVariable(lastNameVariable) .setPush(partialPushPayload); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, Template, TemplateList, merge_data ) client = BasicAuthClient( key='', secret='' ) # Create a new template template = Template(client) template.name = 'Welcome Message' template.description = 'Our welcome message' template.variables = [ { 'key': 'TITLE', 'name': 'Title', 'description': 'e.g., Mr., Ms., Dr., etc.', 'default_value': '' }, { 'key': 'FIRST_NAME', 'name': 'First Name', 'description': 'Given name', 'default_value': None }, { 'key': 'LAST_NAME', 'name': 'Last Name', 'description': 'Family name', 'default_value': None } ] template.push = { 'notification': { 'alert': 'Hello {{TITLE}} {{FIRST_NAME}} {{LAST_NAME}}, this is your welcome message!' } } response = template.create() print(f"Template ID: {template.template_id}") # To get the template ID for future use # List all templates for template in TemplateList(client): print( f"Template ID: {template.template_id}\n" f"Created: {template.created_at}\n" f"Modified: {template.modified_at}\n" f"Last Used: {template.last_used}\n" f"Name: {template.name}\n" f"Description: {template.description}\n" f"Variables: {template.variables}\n" f"Push: {template.push}" ) # Send a push using a template push = client.create_push() push.device_types = ['ios'] push.audience = { 'ios_channel': 'b8f9b663-0a3b-cf45-587a-be880946e881' } push.merge_data = merge_data( template_id='ef34a8d9-0ad7-491c-86b0-aea74da15161', substitutions={ 'FIRST_NAME': 'Bob', 'LAST_NAME': 'Smith', 'TITLE': '' } ) response = push.send() ``` --- ## Delete template {#deletetemplate} Delete a template. If the template is successfully deleted, the response does not include a body. [Jump to examples ↓](#deletetemplate-examples) ### `DELETE /api/templates/{template_id}` {{< note >}} The Personalization (`/templates`) API is deprecated. Instead, [create templates in the Airship dashboard](/docs/guides/personalization/content/templates/) or use the [Content API](/docs/developer/rest-api/ua/operations/content/), and send using the [Bulk sending](/docs/developer/rest-api/ua/operations/bulk-sending/) or [Automation](/docs/developer/rest-api/ua/operations/automation/) APIs. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `template_id` | `string` | Required | A required string ID of the template. | **Responses** **`200`** The template with given ID has been successfully deleted. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` **REQUIRED** If true, the operation completed successfully and returns an expected response. - **`operation_id`** `string` A unique string identifying the operation, useful for reporting and troubleshooting. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http DELETE /api/templates/ef34a8d9-0ad7-491c-86b0-aea74da15161 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "a6394ff8-8a65-4494-ad06-677eb8b7ad6a" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); TemplateDeleteRequest request = TemplateDeleteRequest.newRequest("ef34a8d9-0ad7-491c-86b0-aea74da15161"); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, Template, TemplateList, merge_data ) client = BasicAuthClient( key='', secret='' ) template_id = 'ef34a8d9-0ad7-491c-86b0-aea74da15161' # Delete via template lookup response = Template(client).lookup(template_id).delete() # OR, if you want to delete a template without fetching it from the API response = Template(client).delete(template_id) ``` --- ## List templates {#gettemplates} List all existing templates. Returns an array of template objects in the `templates` attribute. [Jump to examples ↓](#gettemplates-examples) ### `GET /api/templates` {{< note >}} The Personalization (`/templates`) API is deprecated. Instead, [create templates in the Airship dashboard](/docs/guides/personalization/content/templates/) or use the [Content API](/docs/developer/rest-api/ua/operations/content/), and send using the [Bulk sending](/docs/developer/rest-api/ua/operations/bulk-sending/) or [Automation](/docs/developer/rest-api/ua/operations/automation/) APIs. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `page` | `integer` | | Specifies the desired page number. Defaults to 1. | | `page_size` | `integer` | | Specifies how many results to return per page. Has a default value of 25 and a maximum value of 100. | | `sort` | `string` | | Specifies the name of the field you want to sort results by. Defaults to `created_at`. Possible values: `created_at`, `modified_at`, `last_used` | | `order` | `string` | | Specifies the sort order as ascending (`asc`) or descending (`desc`). Defaults to `asc`. Possible values: `asc`, `desc` | **Responses** **`200`** Returned on success, with the JSON representation of the templates in the body of the response. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`count`** `integer` The number of templates in the current response; this is effectively the page size. - **`next_page`** `string` There might be more than one page of results for this listing. Follow this URL if it is present to the next batch of results. Format: `url` Example: `https://go.urbanairship.com/api/templates?page=2&page_size=1` - **`ok`** `boolean` **REQUIRED** Success. - **`prev_page`** `string` Link to the previous page, if available. Format: `url` - **`templates`** `array` <[Template object]({{< ref "/developer/rest-api/ua/schemas/personalization-template-objects/" >}}#templateobject)> An array of template objects. - **`total_count`** `integer` The total number of templates. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/templates HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Data-Attribute: templates Count: 1 Total-Count: 1 Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "count": 1, "total_count": 1, "templates": [ { "id": "ef34a8d9-0ad7-491c-86b0-aea74da15161", "created_at": "2020-08-17T11:10:01Z", "modified_at": "2020-08-17T11:10:01Z", "last_used": null, "name": "Welcome Message", "description": "Our welcome message", "variables": [ { "key": "TITLE", "name": "Title", "description": "e.g., Mr, Ms, Dr, etc.", "default_value": "" }, { "key": "FIRST_NAME", "name": "First Name", "description": "Given name", "default_value": null }, { "key": "LAST_NAME", "name": "Last Name", "description": "Family name", "default_value": null } ], "push": { "notification": { "alert": "Hello {{FIRST_NAME}}, this is your welcome message!" } } } ], "next_page": null, "prev_page": null } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); TemplateListingRequest request = TemplateListingRequest.newRequest(); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, Template, TemplateList, merge_data ) client = BasicAuthClient( key='', secret='' ) # List all templates for template in TemplateList(client): print( f"Template ID: {template.template_id}\n" f"Created: {template.created_at}\n" f"Modified: {template.modified_at}\n" f"Last Used: {template.last_used}\n" f"Name: {template.name}\n" f"Description: {template.description}\n" f"Variables: {template.variables}\n" f"Push: {template.push}" ) ``` --- ## Look up a template {#gettemplate} Fetch the current definition of a single template. [Jump to examples ↓](#gettemplate-examples) ### `GET /api/templates/{template_id}` {{< note >}} The Personalization (`/templates`) API is deprecated. Instead, [create templates in the Airship dashboard](/docs/guides/personalization/content/templates/) or use the [Content API](/docs/developer/rest-api/ua/operations/content/), and send using the [Bulk sending](/docs/developer/rest-api/ua/operations/bulk-sending/) or [Automation](/docs/developer/rest-api/ua/operations/automation/) APIs. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `template_id` | `string` | Required | A required string ID of the template. | **Responses** **`200`** Returned on success, with the JSON representation of the template in the body of the response. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` **REQUIRED** If true, the operation completed successfully and returns an expected response. - **`template`** `object` <[Template object]({{< ref "/developer/rest-api/ua/schemas/personalization-template-objects/" >}}#templateobject)> A template object is a skeleton for a push. This is the object used for template creation, and returned by the template listing and lookup endpoints. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/templates/ef34a8d9-0ad7-491c-86b0-aea74da15161 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Data-Attribute: template Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "template": { "id": "ef34a8d9-0ad7-491c-86b0-aea74da15161", "created_at": "2020-08-17T11:10:02Z", "modified_at": "2020-08-17T11:10:02Z", "last_used": null, "name": "Welcome Message", "description": "Our welcome message", "variables": [ { "key": "TITLE", "name": "Title", "description": "e.g., Mr, Ms, Dr, etc.", "default_value": "" }, { "key": "FIRST_NAME", "name": "First Name", "description": "Given name", "default_value": null }, { "key": "LAST_NAME", "name": "Last Name", "description": "Family name", "default_value": null } ], "push": { "notification": { "alert": "Hello {{FIRST_NAME}}, this is your welcome message!" } } } } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); TemplateListingRequest request = TemplateListingRequest.newRequest("ef34a8d9-0ad7-491c-86b0-aea74da15161"); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, Template, TemplateList, merge_data ) client = BasicAuthClient( key='', secret='' ) template_id = 'ef34a8d9-0ad7-491c-86b0-aea74da15161' template = Template(client).lookup(template_id) print( template.template_id, template.created_at, template.modified_at, template.last_used, template.name, template.description, template.variables, template.push ) ``` --- ## Push to template {#pushtotemplate} Send a push notification based on a template to a list of devices. The body of the request must be a single push template payload or an array of one or more push template payloads. [Jump to examples ↓](#pushtotemplate-examples) ### `POST /api/templates/push` {{< note >}} The Personalization (`/templates`) API is deprecated. Instead, [create templates in the Airship dashboard](/docs/guides/personalization/content/templates/) or use the [Content API](/docs/developer/rest-api/ua/operations/content/), and send using the [Bulk sending](/docs/developer/rest-api/ua/operations/bulk-sending/) or [Automation](/docs/developer/rest-api/ua/operations/automation/) APIs. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): psh **Request body** A single push template payload or an array of push template payloads. Provide an override with any variable that has a `null` default value. For example, if you created a template with the variable `FIRST_NAME`, and that variable has `null` as a default value, you must provide a substitution for `FIRST_NAME` when pushing to that template. **Content-Type:** `application/json` **One of:** - [Push template payload]({{< ref "/developer/rest-api/ua/schemas/personalization-template-objects/" >}}#pushtemplatepayload) A push template payload defines a push by overriding the variables defined in a specific template object. Specifically, a push template object specifies push audience and device types, along with substitutions for the variables defined in a template. - `array` **Responses** **`202`** The push notification has been accepted for processing. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` **REQUIRED** If true, the operation completed successfully and returns an expected response. - **`operation_id`** `string` A unique string identifying the operation, useful for reporting and troubleshooting. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`push_ids`** `array[string]` An array of the push IDs for this operation. Min items: 1, Max items: 100 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/templates/push HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "device_types": [ "ios" ], "audience": { "ios_channel": "b8f9b663-0a3b-cf45-587a-be880946e881" }, "merge_data": { "template_id": "ef34a8d9-0ad7-491c-86b0-aea74da15161", "substitutions": { "FIRST_NAME": "Bob", "LAST_NAME": "Smith", "TITLE": "" } } } ``` ```http HTTP/1.1 202 Accepted Content-Length: 123 Data-Attribute: push_ids Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "operation_id" : "df6a6b50-9843-0304-d5a5-743f246a4946", "push_ids": [ "1cbfbfa2-08d1-92c2-7119-f8f7f670f5f6" ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); TemplatePushPayload payload = TemplatePushPayload.newBuilder() .setAudience(Selectors.iosChannel("b8f9b663-0a3b-cf45-587a-be880946e881")) .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS)) .setMergeData(TemplateSelector.newBuilder() .setTemplateId("ef34a8d9-0ad7-491c-86b0-aea74da15161") .addSubstitution("FIRST_NAME", "Bob") .addSubstitution("LAST_NAME", "Smith") .addSubstitution("TITLE", "Mr.") .build()) .build(); TemplatePushRequest request = TemplatePushRequest.newRequest() .addTemplatePushPayload(payload); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, Template, TemplateList, merge_data ) client = BasicAuthClient( key='', secret='' ) # Send a push using a template push = client.create_push() push.device_types = ['ios'] push.audience = { 'ios_channel': 'b8f9b663-0a3b-cf45-587a-be880946e881' } push.merge_data = merge_data( template_id='ef34a8d9-0ad7-491c-86b0-aea74da15161', substitutions={ 'FIRST_NAME': 'Bob', 'LAST_NAME': 'Smith', 'TITLE': '' } ) response = push.send() ``` --- ## Schedule a templated push {#scheduletemplatedpush} Schedule a push notification based on a template to a list of devices. Like a standard template-based push, the body of the request includes one or more push template payloads along with a schedule object determining when the template-based push should be sent. [Jump to examples ↓](#scheduletemplatedpush-examples) ### `POST /api/templates/schedules` {{< note >}} The Personalization (`/templates`) API is deprecated. Instead, [create templates in the Airship dashboard](/docs/guides/personalization/content/templates/) or use the [Content API](/docs/developer/rest-api/ua/operations/content/), and send using the [Bulk sending](/docs/developer/rest-api/ua/operations/bulk-sending/) or [Automation](/docs/developer/rest-api/ua/operations/automation/) APIs. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): psh **Request body** An array of scheduled pushes. **Content-Type:** `application/json` Type: `array` **Responses** **`202`** The scheduled push has been accepted for processing. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` **REQUIRED** Success. - **`operation_id`** `string` A unique string which identifies a single API call, and can be used to group multiple entities or side effects as related, in reporting and troubleshooting logs. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`schedule_ids`** `array[string]` An array of schedule IDs. Min items: 1, Max items: 100 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` - **`schedule_urls`** `array[string]` An array of schedule URLs. The URL for each schedule is the schedules endpoint, appended with the `schedule_id` of the schedule. Min items: 0, Max items: 100 Example: `https://go.urbanairship/api/schedules/2d69320c-3c91-5241-fac4-248269eed109` - **`schedules`** `array` <[Schedule object]({{< ref "/developer/rest-api/ua/schemas/schedules/" >}}#scheduleobject)> An array of schedule objects. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/templates/schedules HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json [ { "name": "Hello Bob", "schedule": { "scheduled_time": "2020-05-02T22:00:00Z" }, "device_types": [ "ios" ], "audience": { "ios_channel": "b8f9b663-0a3b-cf45-587a-be880946e881" }, "merge_data": { "template_id": "ef34a8d9-0ad7-491c-86b0-aea74da15161", "substitutions": { "FIRST_NAME": "Bob", "LAST_NAME": "Takahashi", "TITLE": null } } }, { "name": "Hello Joe", "schedule": { "scheduled_time": "2020-05-05T18:00:00Z" }, "device_types": [ "android" ], "audience": { "android_channel": "df6a6b50-9843-0304-d5a5-743f246a4946" }, "merge_data": { "template_id": "ef34a8d9-0ad7-491c-86b0-aea74da15161", "substitutions": { "FIRST_NAME": "Joe", "LAST_NAME": "Smith", "TITLE": "Sir" } } } ] ``` ```http HTTP/1.1 202 Accepted Content-Length: 123 Data-Attribute: schedule_urls Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "operation_id" : "efb18e92-9a60-6689-45c2-82fedab36399", "schedule_urls" : [ "http://go.urbanairship/api/schedules/a0cef4f9-1fcd-47ef-b459-01f432b64043", "http://go.urbanairship/api/schedules/fe2dab5e-f837-4707-8d0c-0e8c589ef4cf" ], "schedule_ids" : [ "a0cef4f9-1fcd-47ef-b459-01f432b64043", "fe2dab5e-f837-4707-8d0c-0e8c589ef4cf" ], "schedules" : [ { "url" : "http://go.urbanairship/api/schedules/a0cef4f9-1fcd-47ef-b459-01f432b64043", "name": "Hello Joe", "schedule" : { "..." }, "push" : { "..." }, "push_ids": [ "6a5ecb9c-46ee-4af4-9ced-9308121afaf9" ] }, { "url" : "http://go.urbanairship/api/schedules/fe2dab5e-f837-4707-8d0c-0e8c589ef4cf", "name": "Hello Bob", "schedule" : { "..." }, "push" : { "..." }, "push_ids": [ "5162bbf8-7de7-4040-a64d-e018b71f02f6" ] } ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); TemplateScheduledPushPayload payload = TemplateScheduledPushPayload.newBuilder() .setAudience(Selectors.iosChannel("b8f9b663-0a3b-cf45-587a-be880946e881")) .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS)) .setMergeData(TemplateSelector.newBuilder() .setTemplateId("ef34a8d9-0ad7-491c-86b0-aea74da15161") .addSubstitution("FIRST_NAME", "Bob") .addSubstitution("LAST_NAME", "Takahashi") .addSubstitution("TITLE", "Dr.") .build()) .setSchedule(Schedule.newBuilder() .setScheduledTimestamp(DateTime.parse("2020-05-05T18:00:00Z")) .build()) .build(); TemplateScheduledPushRequest request = TemplateScheduledPushRequest.newRequest() .addTemplateScheduledPushPayload(payload); Response response = client.execute(request); ``` --- ## Update template {#updatetemplate} Update a template. The request body is a partially-defined template object, containing the field(s) you want to change and their updated values. [Jump to examples ↓](#updatetemplate-examples) ### `POST /api/templates/{template_id}` {{< note >}} The Personalization (`/templates`) API is deprecated. Instead, [create templates in the Airship dashboard](/docs/guides/personalization/content/templates/) or use the [Content API](/docs/developer/rest-api/ua/operations/content/), and send using the [Bulk sending](/docs/developer/rest-api/ua/operations/bulk-sending/) or [Automation](/docs/developer/rest-api/ua/operations/automation/) APIs. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `template_id` | `string` | Required | A required string ID of the template. | **Request body** **Content-Type:** `application/json` - **`description`** `string` The description of the template. - **`name`** `string` **REQUIRED** The name of the template. - **`push`** `object` <[Template push object]({{< ref "/developer/rest-api/ua/schemas/personalization-template-objects/" >}}#templatepushobject)> A partial push object describing everything about a push notification, except for the `audience` and `device_types` keys (which are defined in the [Push template payload](/docs/developer/rest-api/ua/schemas/personalization-template-objects/#pushtemplatepayload)) and the `message` key (which is incompatible with templates). - **`variables`** `array` <[Template variables]({{< ref "/developer/rest-api/ua/schemas/personalization-template-objects/" >}}#templatevariableobject)> An array of variable specifications. **Responses** **`200`** Returned if the template has been successfully updated. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` **REQUIRED** If true, the operation completed successfully and returns an expected response. - **`operation_id`** `string` A unique string identifying the operation, useful for reporting and troubleshooting. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/templates/ef34a8d9-0ad7-491c-86b0-aea74da15161 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "name": "Welcome Message", "description": "Our welcome message", "push": { "notification": { "alert": "Hello {{FIRST_NAME}} {{LAST_NAME}}, this is your welcome message!" } } } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "df6a6b50-9843-0304-d5a5-743f246a4946" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); PartialPushPayload partialPushPayload = PartialPushPayload.newBuilder() .setNotification(Notification.newBuilder() .setAlert("Hello {{FIRST_NAME}} {{LAST_NAME}}, this is your welcome message!") .build() ) .build(); TemplateRequest request = TemplateRequest.newRequest("ef34a8d9-0ad7-491c-86b0-aea74da15161") .setName("Welcome Message") .setDescription("Our welcome message") .setPush(partialPushPayload); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, Template, TemplateList, merge_data ) client = BasicAuthClient( key='', secret='' ) template_id = 'ef34a8d9-0ad7-491c-86b0-aea74da15161' updated_template = Template(client) updated_template.push = { 'notification': { 'alert': 'Hi {{FIRST_NAME}} {{LAST_NAME}}!' } } response = updated_template.update(template_id) ``` *Alternatively, call the lookup function on your updated template:* ```python from urbanairship import ( BasicAuthClient, Template, TemplateList, merge_data ) client = BasicAuthClient( key='', secret='' ) template_id = 'ef34a8d9-0ad7-491c-86b0-aea74da15161' updated_template = Template(client).lookup(template_id) updated_template.push = { 'notification': { 'alert': 'Greetings {{TITLE}} {{FIRST_NAME}} {{LAST_NAME}}!' } } response = updated_template.update() ``` --- ## Validate a template {#validatetemplate} This endpoint accepts the same range of payloads as `/api/template/push`, but only parses and validates the payload. It does not actually send a push. [Jump to examples ↓](#validatetemplate-examples) ### `POST /api/templates/push/validate` {{< note >}} The Personalization (`/templates`) API is deprecated. Instead, [create templates in the Airship dashboard](/docs/guides/personalization/content/templates/) or use the [Content API](/docs/developer/rest-api/ua/operations/content/), and send using the [Bulk sending](/docs/developer/rest-api/ua/operations/bulk-sending/) or [Automation](/docs/developer/rest-api/ua/operations/automation/) APIs. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): psh **Request body** A single push template payload or an array of push template payloads. **Content-Type:** `application/json` **One of:** - [Push template payload]({{< ref "/developer/rest-api/ua/schemas/personalization-template-objects/" >}}#pushtemplatepayload) A push template payload defines a push by overriding the variables defined in a specific template object. Specifically, a push template object specifies push audience and device types, along with substitutions for the variables defined in a template. - `array` **Responses** **`200`** The payload was valid. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/templates/push/validate HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "device_types": [ "ios" ], "audience": { "ios_channel": "b8f9b663-0a3b-cf45-587a-be880946e881" }, "merge_data": { "template_id": "ef34a8d9-0ad7-491c-86b0-aea74da15161", "substitutions": { "FIRST_NAME": "Bob", "LAST_NAME": "Smith", "TITLE": "" } } } ``` ```http HTTP/1.1 200 OK Content-Length: 123 Data-Attribute: push_ids Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); TemplatePushPayload payload = TemplatePushPayload.newBuilder() .setAudience(Selectors.iosChannel("b8f9b663-0a3b-cf45-587a-be880946e881")) .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS)) .setMergeData(TemplateSelector.newBuilder() .setTemplateId("ef34a8d9-0ad7-491c-86b0-aea74da15161") .addSubstitution("FIRST_NAME", "Bob") .addSubstitution("LAST_NAME", "Smith") .addSubstitution("TITLE", "Mr.") .build()) .build(); TemplatePushRequest request = TemplatePushRequest.newRequest() .addTemplatePushPayload(payload) .setValidateOnly(true); Response response = client.execute(request); ``` --- # Push > Send notifications or rich messages to supported channels, or validate JSON payloads. ## Delete message from inbox {#deletemessage} Delete a Message Center message completely, removing it from every user’s inbox. This is an asynchronous call; a success response means that the deletion has been queued for processing. This delete call will work with either the `message_id` or the `push_id` of the accompanying push notification. This endpoint will not work with a `group_id` from an automated message or a push to local time delivery. To delete a rich message that was part of an automated or local time delivery, you must use the relevant `push_id` from the operation. [Jump to examples ↓](#deletemessage-examples) ### `DELETE /api/user/messages/{push_id}` {{< note >}} For time-sensitive messages, consider including an `expiry` time as detailed in the [In-App Message Object](/docs/developer/rest-api/ua/schemas/others/#inappobject). Setting an `expiry` value eliminates the need to manually remove messages. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `push_id` | `string` | Required | The `push_id` or `message_id` of the Rich Message you want to delete from users` inboxes. | **Responses** **`202`** The request has been accepted for processing. Response body: **Content-Type:** `application/json` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http DELETE /api/user/messages/(push_id) HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```python from urbanairship import BasicAuthClient, Push client = BasicAuthClient( key='', secret='' ) Push.message_center_delete(airship=client, push_id="941086fd-f7db-493b-a8a7-1f5a7dc6aae4") ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); InboxDeleteRequest request = InboxDeleteRequest.newRequest("68b2d71f-1c10-4592-bd96-2725aee0ae57"); Response response = client.execute(request); ``` --- ## Delete multiple messages from inbox {#batchdeletemessages} Deletes multiple Message Center messages (up to 50 messages per request) completely, removing them from every user’s inbox. This is an asynchronous call; a success response means that the deletion has been queued for processing. It is not possible to delete Message Center messages generated by an automation, a recurring message, or a Sequence. [Jump to examples ↓](#batchdeletemessages-examples) ### `POST /api/user/messages/batch-delete` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) **Request body** A request body containing an array of message IDs to be deleted. **Content-Type:** `application/json` - **`message_ids`** `array[string]` **REQUIRED** Array of Message IDs. Min items: 1, Max items: 50 **Responses** **`202`** The request has been accepted for processing. Response body: **Content-Type:** `application/json` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/user/messages/batch-delete HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "message_ids": [ "drKa4OdxEeyhSwJC9TkdtQ", "W5ersOdxEeyvwAJCxz92iA" ] } ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "deleted_message_ids": [ "W5ersOdxEeyvwAJCxz92iA", "drKa4OdxEeyhSwJC9TkdtQ" ], "errors": [] } ``` ```http HTTP/1.1 404 Not Found Content-Type: application/vnd.urbanairship+json; version=3 { "deleted_message_ids": [], "errors": [ { "message_id": "drKa4OdxEeyhSwJC9Tkdt1", "error_message": "Message not found.", "error_code": 40404 }, { "message_id": "W5ersOdxEeyvwAJCxz92i1", "error_message": "Message not found.", "error_code": 40404 } ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); List arrayList = new ArrayList<>(); arrayList.add("9dWD3LBIS5iZ51Y1GwOi4Q"); arrayList.add("lsDtpTBJTN6KpQTwfOSNbw"); InboxBatchDeleteRequest inboxBatchDeleteRequest = InboxBatchDeleteRequest.newRequest(arrayList); Response response = client.execute(inboxBatchDeleteRequest); ``` --- ## Send a push {#sendpush} Send a push notification to a specified audience. The body of the request must be a [Push object](/docs/developer/rest-api/ua/schemas/others/#pushobject) or an array of push objects. [Jump to examples ↓](#sendpush-examples) ### `POST /api/push` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): psh **Request body** A single push object or an array of push objects. **Content-Type:** `application/json` **One of:** - [Push object]({{< ref "/developer/rest-api/ua/schemas/push/" >}}#pushobject) A push object describes everything about a push notification, including the audience and push payload. A push object is composed of up to seven attributes. - `array` **Responses** **`202`** The push notification has been accepted for processing. The response contains `push_id`, `message_id`, and/or `content_url` arrays based on the type of push. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`content_urls`** `array[string]` An array of URLs where the push payload contains a landing page action. Min items: 0, Max items: 100 - **`localized_ids`** `array[string]` An array of identifiers used for reporting. Each ID represents a localized message (push object with `localizations` array). - **`message_ids`** `array[string]` An array of message IDs, each uniquely identifying a Message Center message. - **`ok`** `boolean` Success. - **`operation_id`** `string` A unique string identifying the operation, useful for reporting and troubleshooting. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`push_ids`** `array[string]` An array of push IDs, each uniquely identifying a push. Min items: 1, Max items: 100 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`413`** Returned when the request is too large to be processed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`429`** Too many requests hit the API too quickly. For example, if we are not ready to create a channel for this payload; e.g., it is rate limited. You should wait before retrying the channel creation. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/push HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "ios_channel": "9c36e8c7-5a73-47c0-9716-99fd3d4197d5" }, "notification": { "alert": "Hello!" }, "device_types": [ "ios" ] } ``` ```http HTTP/1.1 202 Accepted Data-Attribute: push_ids Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "df6a6b50-9843-0304-d5a5-743f246a4946", "push_ids": [ "9d78a53b-b16a-c58f-b78d-181d5e242078" ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); PushPayload payload = PushPayload.newBuilder() .setAudience(Selectors.iosChannel("9c36e8c7-5a73-47c0-9716-99fd3d4197d5")) .setNotification(Notifications.alert("Hello!")) .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS)) .build(); PushRequest request = PushRequest.newRequest(payload); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, Push ) client = BasicAuthClient( key="", secret="" ) push = Push(client) push.audience = {'ios_channel': '9c36e8c7-5a73-47c0-9716-99fd3d4197d5'} push.notification = {'alert': 'Hello!'} push.device_types = ['ios'] push.send() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') push = airship.create_push push.audience = UA.or( UA.ios_channel('9c36e8c7-5a73-47c0-9716-99fd3d4197d5')) push.notification = UA.notification(alert: 'Hello!') push.device_types = UA.device_types(['ios']) push.send_push ``` *Example push with localizations* ```http POST /api/push HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "device_types": [ "ios", "android" ], "audience": { "tag": "needs_a_greeting", "group": "new_customer" }, "notification": { "alert": "Hi!" }, "localizations": [ { "language": "de", "country": "AT", "notification": { "alert": "Grüss Gott" } }, { "language": "de", "country": "DE", "notification": { "alert": "Guten Tag" } } ] } ``` ```http HTTP/1.1 202 Accepted Data-Attribute: push_ids Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "df6a6b50-9843-0304-d5a5-743f246a4946", "push_ids": [ "9d78a53b-b16a-c58f-b78d-181d5e242078", "1cbfbfa2-08d1-92c2-7119-f8f7f670f5f6", "939c3796-a755-413b-a36b-3026b1f92df8" ], "localized_ids": [ "1a38a2ba-c174-d32f-d01b-481a5d241934" ] } ``` ```python from urbanairship import ( BasicAuthClient, Push ) client = BasicAuthClient( key="", secret="" ) push = Push(client) push.audience = { 'tag': 'needs_a_greeting', 'group': 'new_customer' } push.notification = {'alert': 'Hi!'} push.localizations = [ { 'country': 'at', 'language': 'de', 'notification': {'alert': "Grüss Gott"} }, { 'country': 'de', 'language': 'de', 'notification': {'alert': "Guten Tag"} } ] push.device_types = ['ios', 'android'] push.send() ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); Localization localization = Localization.newBuilder() .setCountry("AT") .setLanguage("de") .setNotification(Notifications.alert("Grüss Gott")) .build(); PushPayload payload = PushPayload.newBuilder() .setAudience(Selectors.or(Selectors.tagWithGroup("needs_a_greeting", "new_customer"))) .addLocalization(localization) .setNotification(Notifications.alert("Hi!")) .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS, DeviceType.ANDROID)) .build(); PushRequest request = PushRequest.newRequest(payload); Response response = client.execute(request); ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') push = airship.create_push push.audience = UA.tag("needs_a_greeting", group:'new_customer') push.notification = UA.notification(alert: 'Hi!') push.device_types = UA.device_types(['ios']) push.localizations = { "language": "de", "country": "AT", "notification": { "alert": "Grüss Gott" } } push.send_push ``` *Example email being sent using Push API with template ID* ```http POST /api/push HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "tag": "needs_a_greeting", "group": "new_customer" }, "device_types": [ "email" ], "notification": { "email": { "message_type": "commercial", "reply_to": "no-reply@airship.com", "sender_address": "team@airship.com", "sender_name": "Airship", "template": { "template_id": "876624ff-0120-4364-bf02-dba3d0cb5b85" } } } } ``` ```http HTTP/1.1 202 Accepted Data-Attribute: push_ids Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "be97b696-8d6b-4aec-ac50-c9cfc4be57d6", "push_ids": [ "72ce9ade-aa71-4fbe-b960-246f1a2ca9ee" ], "message_ids": [], "content_urls": [], "localized_ids": [] } ``` --- ## Validate a push {#validatepush} Accept the same range of payloads as POSTing to `/api/push`, but parse and validate only, without sending any pushes. The body of the request must be a [Push Object](/docs/developer/rest-api/ua/schemas/others/#pushobject) or an array of push objects. [Jump to examples ↓](#validatepush-examples) ### `POST /api/push/validate` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): psh **Request body** A single push object or an array of push objects. **Content-Type:** `application/json` **One of:** - [Push object]({{< ref "/developer/rest-api/ua/schemas/push/" >}}#pushobject) A push object describes everything about a push notification, including the audience and push payload. A push object is composed of up to seven attributes. - `array` **Responses** **`200`** The payload was valid. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`413`** Returned when the request is too large to be processed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/push/validate HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "ios_channel": "9c36e8c7-5a73-47c0-9716-99fd3d4197d5" }, "notification": { "alert": "Hello!" }, "device_types": [ "ios" ] } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```python from urbanairship import ( BasicAuthClient, Push ) from urbanairship.push.payload import notification, ios, android, web client = BasicAuthClient( key="", secret="" ) push = Push(client) push.audience = {'ios_channel': '9c36e8c7-5a73-47c0-9716-99fd3d4197d5'} push.notification = notification(alert='Hello!') push.device_types = ['ios'] push.validate() ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); PushPayload payload = PushPayload.newBuilder() .setAudience(Selectors.iosChannel("9c36e8c7-5a73-47c0-9716-99fd3d4197d5")) .setNotification(Notifications.alert("Hello!")) .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS)) .build(); PushRequest request = PushRequest.newRequest(payload).setValidateOnly(true); Response response = client.execute(request); ``` --- # Regions > The Region API endpoints provide a listing and detail for all of your defined entry/exit regions, including custom shapes (polygons) and circles (point/radius). ## Region listing {#getregions} Get a paginated list regions. The result is an array of [Region objects](/docs/developer/rest-api/ua/schemas/regions/#regionobject) under the `"regions"` key. [Jump to examples ↓](#getregions-examples) ### `GET /api/regions` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `limit` | `integer` | | Determines the number of results per page. Defaults to 100, with a maximum of 1,000 regions per page. Setting a `limit` greater than 1,000 returns a 400 response. Max: 1000 | | `start` | `integer` | | A zero-based integer offset into the ordered list of regions, useful for addressing pages directly. | **Responses** **`200`** Returns OK for success. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`count`** `integer` The total number of regions returned. - **`next_page`** `string` There might be more than one page of results for this listing. Follow this URL if it is present to the next batch of results. Format: `url` Example: `https://go.urbanairship.com/api/regions?limit=100&start=100` - **`ok`** `boolean` Success. - **`regions`** `array` <[Region object]({{< ref "/developer/rest-api/ua/schemas/regions/" >}}#regionobject)> An array of region objects. **`400`** Returned when `limit` is greater than 1,000. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/regions/?limit=100&start=100 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Data-Attribute: regions Link: ; rel=next Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "next_page": "https://go.urbanairship.com/api/regions?limit=100&start=100", "count": 100, "regions": [ { "region_id": "abe5deb3-01d0-436e-8c5d-94b6421a01e0", "name": "My Favorite Place", "created_at": "2020-06-09T12:34:56", "updated_at": "2020-06-09T12:34:56", "geofence": { "type": "POLYGON", "points": [ { "latitude": 90.0, "longitude": 120.0 }, { "latitude": 45.0, "longitude": 120.0 }, { "latitude": 0.0, "longitude": 0.0 } ] }, "beacons": [ { "name": "entryway", "id": "VLSHZAOEXOFCMLDVTKFQ" }, { "name": "Exhibit A", "id": "ZAQYMNOZKRFCRPYEUCZI" } ], "attributes": { "store_name": "Tonali's Donuts" }, "source_info": { "source": "GIMBAL", "region_id": "C56654BC0C3243D6A4B7A3673560D6F8", "vendor_href": "https://manager.gimbal.com/api/v2/places/C56654BC0C3243D6A4B7A3673560D6F8" } } ] } ``` --- ## Region lookup {#getregion} Get details for a specific region. [Jump to examples ↓](#getregion-examples) ### `GET /api/regions/{region_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `region_id` | `string` | Required | The region you want to lookup. | **Responses** **`200`** Returns OK for success. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` If true, indicates success. Example: `true` - **`region`** `object` <[Region object]({{< ref "/developer/rest-api/ua/schemas/regions/" >}}#regionobject)> A Region object describes a geographical boundary or set of hardware identifiers and associated attributes that correspond to a physical location of relevance to the application or application owner. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/regions/7d4d9a5c-eff5-40f2-b648-4352c166e878 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Data-Attribute: region Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "region": { "region_id": "7dbd9a5c-eff5-40f2-b648-4352c1668878", "created_at": "2020-08-24T23:15:22.900", "updated_at": "2020-08-24T23:15:22.900", "name": "Alberta Park", "source_info": { "source": "GIMBAL", "region_id": "C56654BC0C3243D6A4B7A3673560D6F8", "vendor_href": "https://manager.gimbal.com/api/v2/places/C56654BC0C3243D6A4B7A3673560D6F8" }, "geofence": { "type": "CIRCLE", "center": { "latitude": 45.56447530000002, "longitude": -122.64461097354126 }, "radius": 200 }, "attributes": { "park_name": "alberta", "type": "park" } } } ``` --- # Reports > Report API endpoints let you retrieve information about push notifications that you have sent. ## Activity log report {#getactivitylogreport} Returns the activity log data, including non-unicast pushes. The series begins with the earliest time given in which the group of pushes were sent. [Jump to examples ↓](#getactivitylogreport-examples) ### `GET /api/reports/activity/details` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `start` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for start of report. | | `end` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for end of report. | | `limit` | `integer` | | Number of results to return per request. Defaults to 100. Results paginate if requesting narrow precision over a long period of time. Min: 1 | **Responses** **`200`** Returned on success. Response body: **Content-Type:** `application/json;` - **`activities`** `array[object]` An array of activity log data. - **`app_key`** `string` The app key for the application. - **`end`** `string` The end [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for the report. Format: `date-time` - **`limit`** `integer` The optional limit for the number of entries to return per request. Defaults to 100. - **`next_page`** `string` There might be more than one page of results for this listing. Follow this URL if it is present to the next batch of results. Format: `url` - **`start`** `string` The start [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for the report. Format: `date-time` **Examples** *Example (response truncated)* ```http GET /api/reports/activity/details?start=2020-06-02T20:47:20&end=2023-01-31T20:47:20 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/json { "app_key": "YOUR_APP_KEY", "start": "2020-06-02T20:47:20", "end": "2023-01-31T20:47:20", "limit": 10, "next_page": "https://go.urbanairship.com/api/reports/activity/details...", "activities": [ { "push_id": "ecb8eaf0-0430-4dfa-93d8-c3149f479d96", "timestamp": "2023-01-31 20:47:20", "type": "GROUP", "experiment": true, "details": { "interaction": { "web": { "clicks": 20, "sessions": 13 }, "app": { "influenced": 13, "direct": 12, "indirect": 10, "rich_read": 5 } }, "delivery": { "web": { "total": 13 }, "app": { "silent": 125, "alerting": 13, "rich": 5, "in_app": { "impressions": 10, "impressions_opted_in": 5, "impressions_opted_out": 5 } } } } } ] } ``` --- ## App opens report {#getappopensreport} Get the number of users who have opened your app within the specified time period. [Jump to examples ↓](#getappopensreport-examples) ### `GET /api/reports/opens` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `start` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for start of report. | | `end` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for end of report. | | `precision` | `string` | Required | Granularity of results to return. Defaults to `DAILY`. Possible values: `HOURLY`, `DAILY`, `MONTHLY` Default: `DAILY` | **Responses** **`200`** Returned on success, with the JSON representation of the app opens in the body of the response. Response body: **Content-Type:** `application/json;` - **`next_page`** `string` There might be more than one page of results for this listing. Follow this URL if it is present to the next batch of results. Format: `url` - **`opens`** `array[object]` An array of App opens objects. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/reports/opens?start=2020-08-01T10:00&end=2020-08-15T20:00&precision=MONTHLY HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "opens": [ { "date": "2020-08-01 00:00:00", "ios": 350, "android": 250 } ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); PlatformStatsRequest request = PlatformStatsRequest.newRequest(PlatformStatsRequestType.APP_OPENS) .setStart(DateTime.parse("2020-08-01T10:34:22Z")) .setEnd(DateTime.parse("2020-08-15T10:34:22Z")) .setPrecision(Precision.MONTHLY); Response response = client.execute(request); ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, AppOpensList ) client = BasicAuthClient( key='', secret='' ) start_date = datetime(2020, 8, 1) end_date = datetime(2020, 8, 15) for open in AppOpensList(airship=client, start_date=start_date, end_date=end_date, precision='DAILY'): print(open) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') listing = UA::AppOpensList.new( client: airship, start_date: '2020-08-01', end_date: '2020-08-15', precision: 'MONTHLY') listing.each do |app_opens| puts(app_opens) end ``` --- ## Custom Events detail listing {#getcustomeventsreport} Get a summary of Custom Event counts and values, by Custom Event, within the specified time period. [Jump to examples ↓](#getcustomeventsreport-examples) ### `GET /api/reports/events` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `start` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for start of report. | | `end` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for end of report. | | `precision` | `string` | | Granularity of results to return. Defaults to `DAILY`. Possible values: `HOURLY`, `DAILY`, `MONTHLY` Default: `DAILY` | | `page` | `integer` | | Identifies the desired page number. Defaults to 1. If page is given a negative or out of bounds value, the default value will be used. | | `page_size` | `integer` | | Specifies how many results to return per page. Has a default value of 25 and a maximum value of 100. | **Responses** **`200`** Returned on success, with the JSON representation of the events in the body of the response. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`events`** `array[object]` An array of Custom Events and its details. - **`next_page`** `string` There might be more than one page of results for this listing. Follow this URL if it is present to the next batch of results. Format: `url` - **`ok`** `boolean` Success. - **`prev_page`** `string` Link to the previous page, if available. Format: `url` - **`total_count`** `integer` Sum of all the count fields in the above array. Example: `12` - **`total_value`** `integer` Sum of all the value fields in the above array. Example: `321.2` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/reports/events?start=2020-08-01T10:00:00.000Z&end=2020-08-15T20:00:00.000Z&precision=MONTHLY&page_size=20 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "total_value": 2, "total_count": 709, "next_page": "https://go.urbanairship.com/api/reports/events?start=2020-08-01T10:00:00.000Z&end=2020-08-15T20:00:00.000Z&precision=MONTHLY&page_size=20&page=2", "events": [ { "name": "banner_image", "conversion": "indirect", "location": "ua_mcrap", "count": 1, "value": 1 }, { "name": "bounce", "conversion": "direct", "location": "custom", "count": 23, "value": 0 }, { "name": "button-click-Do it ", "conversion": "direct", "location": "in_app_message", "count": 1, "value": 0 }, { "name": "button-click-Get Notifications", "conversion": "unattributed", "location": "in_app_message", "count": 3, "value": 0 }, { "name": "button-click-RATE NOW", "conversion": "direct", "location": "in_app_message", "count": 1, "value": 0 }, { "name": "button-click-Rate the app.", "conversion": "direct", "location": "in_app_message", "count": 1, "value": 0 } ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); DateTime startDate = DateTime.parse("2022-01-01T10:00:00"); DateTime endDate = DateTime.parse("2023-01-01T10:00:00"); CustomEventsDetailsListingRequest customEventsDetailsListingRequest = CustomEventsDetailsListingRequest .newRequest(startDate, endDate) .setPageSize(10) .setPrecision(Precision.MONTHLY) .setPage(2); Response response = client.execute(customEventsDetailsListingRequest); List customEventsDetailResponses = response.getBody().get().getEvents().get(); ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, CustomEventsList ) client = BasicAuthClient( key='', secret='' ) start_date = datetime(2020, 8, 1) end_date = datetime(2020, 8, 15) for event in CustomEventsList(airship=client, start_date=start_date, end_date=end_date, precision='MONTHLY'): print(event) ``` --- ## Custom Events per group summary {#getcustomeventspergroupsummary} Get a summary of Custom Event counts and values associated with the provided Push ID. Includes all Custom Events from the time of the push up to current time. [Jump to examples ↓](#getcustomeventspergroupsummary-examples) ### `GET /api/reports/events/summary/pergroup/{group_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `group_id` | `string` | Required | The UUID for the requested group push ID. | **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `variant` | `integer` | | Variant number (0 to 25), or -1 for control events. | | `page` | `integer` | | Identifies the desired page number. Defaults to 1. If page is given a negative or out of bounds value, the default value will be used. | | `page_size` | `integer` | | Specifies how many results to return per page. Has a default value of 25 and a maximum value of 100. | **Responses** **`200`** Returned on success, with the JSON representation of the events in the body of the response. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` **All of:** - **`group_id`** `string` The UUID representing a specific group push. Format: `uuid` - **`events`** `array[object]` An array of Custom Events and its details. - **`next_page`** `string` There might be more than one page of results for this listing. Follow this URL if it is present to the next batch of results. Will only be present if there are successive pages. Format: `url` - **`ok`** `boolean` Success. - **`prev_page`** `string` Link to the previous page, if available. Will only be present if there are preceding pages. Format: `url` - **`total_count`** `integer` Sum of all the count fields in the above array. Example: `12` - **`total_value`** `integer` Sum of all the value fields in the above array. Example: `321.2` - **`variant`** `integer` Variant number (0 to 25) or -1 for control events. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example request* ```http GET /api/reports/events/summary/pergroup/8bd09679-f672-4783-a31a-d4e516f9e99c HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` *Response with Group ID parameter* ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "group_id": "8bd09679-f672-4783-a31a-d4e516f9e99c", "events": [ { "name": "custom_event_name", "location": "custom", "conversion": "direct", "count": 4, "value": 16.4 }, ... ], "total_count": 12, "total_value": 321.2, "next_page": "https://go.urbanairship.com/api/reports/events/summary/pergroup/...", "prev_page": "https://go.urbanairship.com/api/reports/events/summary/pergroup/..." } ``` --- ## Custom Events per push summary {#getcustomeventsperpushsummary} Get a summary of Custom Event counts and values associated with the provided Push ID. Includes all Custom Events from the time of the push up to current time. [Jump to examples ↓](#getcustomeventsperpushsummary-examples) ### `GET /api/reports/events/summary/perpush/{push_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `push_id` | `string` | Required | The UUID for the requested push. | **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `variant` | `integer` | | Variant number (0 to 25), or -1 for control events. | | `page` | `integer` | | Identifies the desired page number. Defaults to 1. If page is given a negative or out of bounds value, the default value will be used. | | `page_size` | `integer` | | Specifies how many results to return per page. Has a default value of 25 and a maximum value of 100. | **Responses** **`200`** Returned on success, with the JSON representation of the events in the body of the response. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` **All of:** - **`push_id`** `string` The UUID representing a specific push. Format: `uuid` - **`events`** `array[object]` An array of Custom Events and its details. - **`next_page`** `string` There might be more than one page of results for this listing. Follow this URL if it is present to the next batch of results. Will only be present if there are successive pages. Format: `url` - **`ok`** `boolean` Success. - **`prev_page`** `string` Link to the previous page, if available. Will only be present if there are preceding pages. Format: `url` - **`total_count`** `integer` Sum of all the count fields in the above array. Example: `12` - **`total_value`** `integer` Sum of all the value fields in the above array. Example: `321.2` - **`variant`** `integer` Variant number (0 to 25) or -1 for control events. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example request* ```http GET /api/reports/events/summary/perpush/8bd09679-f672-4783-a31a-d4e516f9e99c HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` *Response with Push ID parameter* ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "push_id": "8bd09679-f672-4783-a31a-d4e516f9e99c", "events": [ { "name": "custom_event_name", "location": "custom", "conversion": "direct", "count": 4, "value": 16.4 }, ... ], "total_count": 12, "total_value": 321.2, "next_page": "https://go.urbanairship.com/api/reports/events/summary/perpush/...", "prev_page": "https://go.urbanairship.com/api/reports/events/summary/perpush/..." } ``` *Response with variant parameter* ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "push_id": "8bd09679-f672-4783-a31a-d4e516f9e99c", "variant": 1, "events": [ { "name": "custom_event_name", "location": "custom", "conversion": "direct", "count": 4, "value": 16.4 }, ... ], "total_count": 12, "total_value": 321.2, "next_page": "https://go.urbanairship.com/api/reports/events/summary/perpush/...", "prev_page": "https://go.urbanairship.com/api/reports/events/summary/perpush/..." } ``` --- ## Devices report {#getdevicesreport} Get an app's opted-in and installed device counts by device type. [Jump to examples ↓](#getdevicesreport-examples) ### `GET /api/reports/devices` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `date` | `string` | Required | All device events counted occurred before this [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format). | **Responses** **`200`** Returned on success, with the JSON representation of the device counts in the body of the response. Response body: **Content-Type:** `application/json;` - **`counts`** `object` The counts for each device type. **OBJECT PROPERTIES** - **`amazon`** `object` The count object for a device type. **OBJECT PROPERTIES** - **`opted_in`** `integer` Opted in to receiving push notifications. Example: `140` - **`opted_out`** `integer` Opted out of receiving push notifications. Example: `89` - **`uninstalled`** `integer` Devices for which Reports has seen an uninstall event. Example: `9` - **`unique_devices`** `integer` Devices considered by Airship Reports to have the app installed. Example: `229` - **`android`** `object` The count object for a device type. **OBJECT PROPERTIES** - **`opted_in`** `integer` Opted in to receiving push notifications. Example: `140` - **`opted_out`** `integer` Opted out of receiving push notifications. Example: `89` - **`uninstalled`** `integer` Devices for which Reports has seen an uninstall event. Example: `9` - **`unique_devices`** `integer` Devices considered by Airship Reports to have the app installed. Example: `229` - **`ios`** `object` The count object for a device type. **OBJECT PROPERTIES** - **`opted_in`** `integer` Opted in to receiving push notifications. Example: `140` - **`opted_out`** `integer` Opted out of receiving push notifications. Example: `89` - **`uninstalled`** `integer` Devices for which Reports has seen an uninstall event. Example: `9` - **`unique_devices`** `integer` Devices considered by Airship Reports to have the app installed. Example: `229` - **`date_closed`** `string` All device events counted occurred before this [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format). Format: `date-time` Example: `2018-06-06 11:47:51` - **`date_computed`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) the device event data was tallied and stored. Format: `date-time` Example: `2018-06-07 11:47:51` - **`total_unique_devices`** `integer` Sum of the unique devices for every device type. Example: `12545` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/reports/devices?date=2020-08-28T00:00:00 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "total_unique_devices": 13186, "date_closed": "2020-08-28 00:00:00", "date_computed": "2020-08-29 13:30:45", "counts": { "ios": { "unique_devices": 231, "opted_in": 142, "opted_out": 89, "uninstalled": 2096 }, "android": { "unique_devices": 11795, "opted_in": 226, "opted_out": 11569, "uninstalled": 1069 }, "amazon": { "unique_devices": 29, "opted_in": 22, "opted_out": 7, "uninstalled": 9 }, "sms": { "unique_devices": 26, "opted_in": 23, "opted_out": 3, "uninstalled": 17 } } } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); DevicesReportRequest request = DevicesReportRequest.newRequest() .setDate(DateTime.parse("2020-08-28T10:34:22Z")); Response response = client.execute(request); ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, DevicesReport ) client = BasicAuthClient( key='', secret='' ) date = datetime(2020, 8, 28) response = DevicesReport(airship=client).get(date=date) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') d = UA::DevicesReport.new(client: airship) devices = d.get(date: '2020/08/28') ``` --- ## Experiment overview report {#getexperimentoverviewreport} Returns statistics and metadata about an experiment (A/B Test). [Jump to examples ↓](#getexperimentoverviewreport-examples) ### `GET /api/reports/experiment/overview/{push_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `push_id` | `string` | Required | The `push_id` of the requested experiment. | **Responses** **`200`** Returned on success. Response body: **Content-Type:** `application/json;` - **`app_key`** `string` The app key for the given `push_id`. - **`control`** `object` JSON object describing the control group, i.e., those devices that receive no notification, for the experiment. **OBJECT PROPERTIES** - **`audience_pct`** `number` The percentage of the total audience belonging to the control group. - **`response_rate_pct`** `number` The response rate from the control group. - **`responses`** `integer` The number of responses from the control group. Example: `123` - **`sends`** `integer` The number of pushes sent to native mobile platforms, e.g., iOS. Exclusive of `open_channel_sends`, which are broken out under `open_channel_sends`. Example: `123` - **`direct_responses`** `integer` The number of direct responses to the experiment. - **`experiment_id`** `string` ID for the requested experiment. Format: `uuid` - **`influenced_responses`** `integer` The number of influenced responses to the experiment. - **`variants`** `object` Single variant reporting object or array of variant reporting objects, including associated metadata, audience percentage and response statistics. **OBJECT PROPERTIES** - **`audience_pct`** `number` - **`direct_response_pct`** `number` The percentage direct responses to the notification measured by the SDK. Example: `13.44` - **`direct_responses`** `integer` The number of direct responses to the variant measured by the SDK. Example: `45` - **`id`** `integer` - **`indirect_response_pct`** `number` The percentage indirect responses to the notification measured by the SDK. Example: `0` - **`indirect_responses`** `integer` The number of indirect responses to the variant measured by the SDK. Example: `0` - **`name`** `string` - **`sends`** `integer` The number of pushes sent SDK-supporting platforms, e.g., iOS, Android, and Web. Exclusive of `open_channel_sends`, which are broken out under `open_channel_sends`. Example: `123` - **`web_clicks`** `integer` The number of web notifications that the audience clicked on. - **`web_sessions`** `integer` The total number of web sessions that resulted in a notification. Use in conjunction with `web_clicks` to determine the effectiveness of your web notification experiments. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/reports/experiment/overview/b43ae1b2-3ff6-4c02-adb2-79deac0bbb19 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "app_key": "some_app_key", "experiment_id": "a7806815-6483-4cb9-9d74-bc3b4f3dc1b8", "push_id": "b43ae1b2-3ff6-4c02-adb2-79deac0bbb19", "created": "2020-02-25 23:03:12", "sends": 532, "direct_responses": 50, "influenced_responses": 60, "web_clicks": 6, "web_sessions": 8, "variants": [ { "id" : 0, "name": "call to action", "audience_pct": 45.0, "sends": 238, "direct_responses": 32, "direct_response_pct": 13.44, "indirect_responses": 0, "indirect_response_pct": 0.0 }, { "id" : 1, "name": "gentle reminder", "audience_pct": 45.0, "sends": 251, "direct_responses": 20, "direct_response_pct": 7.97, "indirect_responses": 4, "indirect_response_pct": 1.59 } ], "control": { "audience_pct": 10.0, "sends": 50, "responses": 1, "response_rate_pct": 2.0 } } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); ExperimentOverviewReportRequest experimentOverviewReportRequest = ExperimentOverviewReportRequest.newRequest("4b83d756-cc64-45e0-b140-3f5ec04170fb"); Response response = client.execute(experimentOverviewReportRequest); ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, ExperimentReport ) client = BasicAuthClient( key='', secret='' ) experiment_report = ExperimentReport(airship=client) overview_report = experiment_report.get_overview( push_id="b43ae1b2-3ff6-4c02-adb2-79deac0bbb19" ) print(overview_report) ``` --- ## Experiment variant report {#getexperimentvariantreport} Returns statistics and metadata about a specific variant in an experiment (A/B Test). [Jump to examples ↓](#getexperimentvariantreport-examples) ### `GET /api/reports/experiment/detail/{push_id}/{variant_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `push_id` | `string` | Required | The `push_id` of the requested experiment. | | `variant_id` | `integer` | Required | The specific variant you want to return results for. Min: 1 Max: 26 | **Responses** **`200`** Returned on success. Response body: **Content-Type:** `application/json;` - **`app_key`** `string` The app key for the given `push_id`. - **`created`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when the variant was created. Format: `date-time` Read only: true - **`direct_responses`** `integer` The number of direct responses to the variant. - **`experiment_id`** `string` ID of the experiment that the variant belongs to. Format: `uuid` - **`influenced_responses`** `integer` The total number of influenced responses to the variant. - **`platforms`** `object` **OBJECT PROPERTIES** - **`amazon`** `object` **OBJECT PROPERTIES** - **`direct_responses`** `integer` The number of direct responses (clicks/app opens) to the variant notification on this platform as measured by the SDK. - **`influenced_responses`** `integer` The number of opens or clicks resulting from your notification (directly or indirectly). - **`sends`** `integer` The total number of audience members that accounted the variant on the specified platform. - **`android`** `object` **OBJECT PROPERTIES** - **`direct_responses`** `integer` The number of direct responses (clicks/app opens) to the variant notification on this platform as measured by the SDK. - **`influenced_responses`** `integer` The number of opens or clicks resulting from your notification (directly or indirectly). - **`sends`** `integer` The total number of audience members that accounted the variant on the specified platform. - **`ios`** `object` **OBJECT PROPERTIES** - **`direct_responses`** `integer` The number of direct responses (clicks/app opens) to the variant notification on this platform as measured by the SDK. - **`influenced_responses`** `integer` The number of opens or clicks resulting from your notification (directly or indirectly). - **`sends`** `integer` The total number of audience members that accounted the variant on the specified platform. - **`web`** `object` **OBJECT PROPERTIES** - **`direct_responses`** `integer` The number of direct responses (clicks/app opens) to the variant notification on this platform as measured by the SDK. - **`influenced_responses`** `integer` The number of opens or clicks resulting from your notification (directly or indirectly). - **`sends`** `integer` The total number of audience members that accounted the variant on the specified platform. - **`push_id`** `string` The specific push_id that the variant belonged to. Format: `uuid` - **`variant`** `integer` The individual variant you want to return results for. Variants are ordered 1-26 in the order that they are arranged in the `variants` array when you created the experiment. Min: 1, Max: 26 - **`variant_name`** `string` The name of the variant specified in the endpoint. **Examples** *Example* ```http GET /api/reports/experiment/detail/b43ae1b2-3ff6-4c02-adb2-79deac0bbb19/2 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "app_key": "some_app_key", "experiment_id": "a7806815-6483-4cb9-9d74-bc3b4f3dc1b8", "push_id": "b43ae1b2-3ff6-4c02-adb2-79deac0bbb19", "created": "2020-02-25 23:03:12", "variant": 2, "variant_name": "thing_two", "sends": 64, "direct_responses": 3, "influenced_responses": 1, "platforms": { "android": { "direct_responses": 0, "influenced_responses": 0, "sends": 22 }, "ios": { "direct_responses": 0, "influenced_responses": 1, "sends": 36 }, "amazon": { "direct_responses": 0, "influenced_responses": 0, "sends": 0 }, "web": { "direct_responses": 3, "indirect_responses": 0, "sends": 6 } } } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); ExperimentVariantReportRequest experimentVariantReportRequest = ExperimentVariantReportRequest.newRequest("b43ae1b2-3ff6-4c02-adb2-79deac0bbb19", "1"); Response response = client.execute(experimentVariantReportRequest); ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, ExperimentReport ) client = BasicAuthClient( key='', secret='' ) experiment_report = ExperimentReport(airship=client) variant_report = experiment_report.get_variant( push_id="b43ae1b2-3ff6-4c02-adb2-79deac0bbb19", variant=2 ) print(variant_report) ``` --- ## Individual push response statistics {#getresponsesforpush} Returns detailed reports information about a specific push notification. Use the `push_id`, which is the identifier returned by the API that represents a specific push message delivery. [Jump to examples ↓](#getresponsesforpush-examples) ### `GET /api/reports/responses/{push_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `push_id` | `string` | Required | The UUID for the requested push. | **Responses** **`200`** Returned on success, with the JSON representation of the push statistics in the body of the response. Response body: **Content-Type:** `application/json;` - **`direct_responses`** `integer` The number of native-platform direct responses to the notification measured by the SDK. Example: `45` - **`open_channels_sends`** `object` Contains an array of the number of send counts per open platform. If there were no open channels sends associated with the push ID, an empty result will be returned. **OBJECT PROPERTIES** - **`platforms`** `array[object]` An array of objects indicating the total sends by open platform. - **`push_time`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) indicating the time that the push was initially sent. Format: `date-time` Example: `2018-06-02 10:00:00` - **`push_type`** `string` This string describes the push operation, which is often comparable to the audience selection. Possible values: `BROADCAST_PUSH`, `TAG_PUSH`, `SCHEDULED_PUSH`, `SEGMENTS_PUSH`, `UNICAST_PUSH` Example: `TAG_PUSH` - **`push_uuid`** `string` The UUID for the requested push. Format: `uuid` Example: `f133a7c8-d750-11e1-a6cf-e06995b6c872` - **`sends`** `integer` The number of pushes sent to native mobile platforms, e.g., iOS. Exclusive of `open_channel_sends`, which are broken out under `open_channel_sends`. Example: `123` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/reports/responses/90f28bc6-6c9b-4c99-b970-973afc266e08 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "push_uuid": "90f28bc6-6c9b-4c99-b970-973afc266e08", "push_time": "2020-02-25 23:03:12", "push_type": "UNICAST_PUSH", "sends": 167, "direct_responses": 15, "open_channels_sends": { "platforms": [ { "id": "PLATFORM_NAME", "sends": 22 }, { "id": "ANOTHER_PLATFORM", "sends": 145 } ] } } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); PushInfoRequest request = PushInfoRequest.newRequest("90f28bc6-6c9b-4c99-b970-973afc266e08"); Response response = client.execute(request); PushInfoResponse pushInfo = response.getBody().get(); // Number of sends int sends = pushInfo.getSends(); // Number of direct responses to the push int directResponses = pushInfo.getDirectResponses(); // When the push was sent DateTime date = pushInfo.getPushTime(); // The push type - can be one of BROADCAST_PUSH, SCHEDULED_PUSH, TAG_PUSH, UNICAST_PUSH PushInfoResponse.PushType type = pushInfo.getPushType(); // The unique identifier for the push UUID pushId = pushInfo.getPushId(); ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, IndividualResponseStats ) client = BasicAuthClient( key='', secret='' ) push_id = '90f28bc6-6c9b-4c99-b970-973afc266e08' response = IndividualResponseStats(airship=client).get(push_id) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') d = UA::IndividualResponseStats.new(client: airship) statistics = d.get(push_id: '90f28bc6-6c9b-4c99-b970-973afc266e08') ``` --- ## Opt-in report {#getoptinreport} Get the number of opted-in Push users who access the app within the specified time period. [Jump to examples ↓](#getoptinreport-examples) ### `GET /api/reports/optins` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `start` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for start of report. | | `end` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for end of report. | | `precision` | `string` | Required | Granularity of results to return. Defaults to `DAILY`. Possible values: `HOURLY`, `DAILY`, `MONTHLY` Default: `DAILY` | **Responses** **`200`** Returned on success, with the JSON representation of the opt-ins in the body of the response. Response body: **Content-Type:** `application/json;` - **`next_page`** `string` There might be more than one page of results for this listing. Follow this URL if it is present to the next batch of results. Format: `url` - **`optins`** `array[object]` An array of OptIn objects. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/reports/optins?start=2020-08-01T10:00&end=2020-08-15T20:00&precision=MONTHLY HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "optins": [ { "android": 50, "date": "2020-05-01 00:00:00", "ios": 500 } ], "next_page": "https://go.urbanairship.com/api/reports/..." } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); PlatformStatsRequest request = PlatformStatsRequest.newRequest(PlatformStatsRequestType.OPT_INS) .setStart(DateTime.parse("2020-08-01T10:34:22Z")) .setEnd(DateTime.parse("2020-08-15T10:34:22Z")) .setPrecision(Precision.MONTHLY); Response response = client.execute(request); ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, OptInList ) client = BasicAuthClient( key='', secret='' ) start_date = datetime(2020, 8, 1) end_date = datetime(2020, 8, 15) for opt_in in OptInList(airship=client, start_date=start_date, end_date=end_date, precision='DAILY'): print(opt_in) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') listing = UA::OptInList.new( client: airship, start_date: '2020-08-01', end_date: '2020-08-15', precision: 'MONTHLY') listing.each do |opt_ins| puts(opt_ins) end ``` --- ## Opt-out report {#getoptoutreport} Get the number of opted-out Push users who access the app within the specified time period. [Jump to examples ↓](#getoptoutreport-examples) ### `GET /api/reports/optouts` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `start` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for start of report. | | `end` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for end of report. | | `precision` | `string` | Required | Granularity of results to return. Defaults to `DAILY`. Possible values: `HOURLY`, `DAILY`, `MONTHLY` Default: `DAILY` | **Responses** **`200`** Returned on success, with the JSON representation of the opt-outs in the body of the response. Response body: **Content-Type:** `application/json;` - **`next_page`** `string` There might be more than one page of results for this listing. Follow this URL if it is present to the next batch of results. Format: `url` - **`optouts`** `array[object]` An array of OptOut objects. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/reports/optouts?start=2020-08-01T10:00&end=2020-08-15T20:00&precision=MONTHLY HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "optouts": [ { "android": 5, "date": "2020-05-01 00:00:00", "ios": 25 } ], "next_page": "https://go.urbanairship.com/api/reports/..." } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); PlatformStatsRequest request = PlatformStatsRequest.newRequest(PlatformStatsRequestType.OPT_OUTS) .setStart(DateTime.parse("2020-08-01T10:34:22Z")) .setEnd(DateTime.parse("2020-08-15T10:34:22Z")) .setPrecision(Precision.MONTHLY); Response response = client.execute(request); ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, OptOutList ) client = BasicAuthClient( key='', secret='' ) start_date = datetime(2020, 8, 1) end_date = datetime(2020, 8, 15) for opt_out in OptOutList(airship=client, start_date=start_date, end_date=end_date, precision='DAILY'): print(opt_out) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') listing = UA::OptOutList.new( client: airship, start_date: '2020-08-01', end_date: '2020-08-15', precision: 'MONTHLY') listing.each do |opt_outs| puts(opt_outs) end ``` --- ## Per group push detail report {#getpergrouppushdetailreport} Returns statistics and other information for a given group push message. [Jump to examples ↓](#getpergrouppushdetailreport-examples) ### `GET /api/reports/pergroup/detail/{group_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `group_id` | `string` | Required | The `group_id` of the requested report. | **Responses** **`200`** Returned on success. Response body: **Content-Type:** `application/json;` **All of:** - **`group_id`** `string` The UUID representing a specific group push. Format: `uuid` - **`alerting_sends`** `integer` The number of alerting sends. - **`app_key`** `string` The app key for the given push. - **`created`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when the push was created. Format: `date-time` Read only: true - **`direct_responses`** `integer` The number of direct responses. - **`influenced_responses`** `integer` The total number of influenced responses. - **`platforms`** `object` **OBJECT PROPERTIES** - **`amazon`** `object` **OBJECT PROPERTIES** - **`direct_responses`** `integer` The number of direct responses (clicks/app opens) to the notification on this platform as measured by the SDK. - **`influenced_responses`** `integer` The number of opens or clicks resulting from your notification (directly or indirectly). - **`sends`** `integer` The total number of audience members accounted on the specified platform. - **`android`** `object` **OBJECT PROPERTIES** - **`direct_responses`** `integer` The number of direct responses (clicks/app opens) to the notification on this platform as measured by the SDK. - **`influenced_responses`** `integer` The number of opens or clicks resulting from your notification (directly or indirectly). - **`sends`** `integer` The total number of audience members accounted on the specified platform. - **`ios`** `object` **OBJECT PROPERTIES** - **`direct_responses`** `integer` The number of direct responses (clicks/app opens) to the notification on this platform as measured by the SDK. - **`influenced_responses`** `integer` The number of opens or clicks resulting from your notification (directly or indirectly). - **`sends`** `integer` The total number of audience members accounted on the specified platform. - **`web`** `object` **OBJECT PROPERTIES** - **`direct_responses`** `integer` The number of direct responses (clicks/app opens) to the notification on this platform as measured by the SDK. - **`influenced_responses`** `integer` The number of opens or clicks resulting from your notification (directly or indirectly). - **`sends`** `integer` The total number of audience members accounted on the specified platform. - **`rich_deletions`** `integer` The number of rich deletions. - **`rich_responses`** `integer` The number of rich responses. - **`rich_sends`** `integer` The number of rich sends. - **`sends`** `integer` The number of pushes sent. - **`silent_sends`** `integer` The number of silent sends. **Examples** *Example* ```http GET /api/reports/pergroup/detail/57ef3728-79dc-46b1-a6b9-20081e561f97 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/json { "app_key": "some_app_key", "group_id": "57ef3728-79dc-46b1-a6b9-20081e561f97", "created": "2023-07-25 23:03:12", "rich_deletions": 0, "rich_responses": 0, "rich_sends": 0, "sends": 103, "alerting_sends": 103, "silent_sends": 0, "direct_responses": 0, "influenced_responses": 3, "platforms": { "android": { "direct_responses": 0, "influenced_responses": 0, "sends": 22 }, "ios": { "direct_responses": 0, "influenced_responses": 1, "sends": 36 }, "amazon": { "direct_responses": 0, "influenced_responses": 1, "sends": 5 }, "web": { "direct_responses": 0, "influenced_responses": 1, "sends": 40 } } } ``` --- ## Per group push time series report {#getpergrouppushtimeseriesreport} Returns the default time series data (hourly precision for 12 hours) for a given group push message. The series begins with the hour in which the push was sent. By specifying the precision without providing a time range, the default number of periods at each precision returned are as follows: Hourly: 12, Daily: 7, Monthly: 3. Results paginate if requesting narrow precision over a long period of time. [Jump to examples ↓](#getpergrouppushtimeseriesreport-examples) ### `GET /api/reports/pergroup/series/{group_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `group_id` | `string` | Required | The `group_id` of the requested report. | **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `precision` | `string` | | The precision of the report. Defaults to `HOURLY`. Possible values: `HOURLY`, `DAILY`, `MONTHLY` | | `start` | `string` | | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for start of report. | | `end` | `string` | | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for end of report. | **Responses** **`200`** Returned on success. Response body: **Content-Type:** `application/json;` **All of:** - **`group_id`** `string` The UUID representing a specific group push. Format: `uuid` - **`app_key`** `string` The app key for the application. Example: `your_app_key` - **`end`** `string` The end [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for the report. Format: `date-time` Example: `2018-06-02 10:00:00` - **`precision`** `string` The precision of the report. Possible values: `HOURLY`, `DAILY`, `MONTHLY` Example: `HOURLY` - **`start`** `string` The start [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for the report. Format: `date-time` Example: `2018-06-01 10:00:00` - **`counts`** `array[object]` Array of total count objects, each representing counts within the given [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) range and precision. **Examples** *Example (response truncated to 2 items)* ```http GET /api/reports/pergroup/series/57ef3728-79dc-46b1-a6b9-20081e561f97 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/json { "app_key": "some_app_key", "group_id": "57ef3728-79dc-46b1-a6b9-20081e561f97", "start": "2023-07-25 23:00:00", "end": "2023-07-26 11:00:00", "precision": "HOURLY", "counts": [ { "push_platforms": { "all": { "direct_responses": 0, "influenced_responses": 1, "sends": 58 }, "android": { "direct_responses": 0, "influenced_responses": 0, "sends": 22 }, "ios": { "direct_responses": 0, "influenced_responses": 1, "sends": 36 } }, "rich_push_platforms": { "all": { "responses": 0, "sends": 0 } }, "time": "2023-07-25 23:00:00" }, { "push_platforms": { "all": { "direct_responses": 0, "influenced_responses": 0, "sends": 0 }, "android": { "direct_responses": 0, "influenced_responses": 0, "sends": 0 }, "ios": { "direct_responses": 0, "influenced_responses": 0, "sends": 0 } }, "rich_push_platforms": { "all": { "responses": 0, "sends": 0 } }, "time": "2023-07-26 00:00:00" } ] } ``` --- ## Per push detail report {#getperpushdetailreport} Returns statistics and other information for a given push message. [Jump to examples ↓](#getperpushdetailreport-examples) ### `GET /api/reports/perpush/detail/{push_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `push_id` | `string` | Required | The `push_id` of the requested report. | **Responses** **`200`** Returned on success. Response body: **Content-Type:** `application/json;` **All of:** - **`push_id`** `string` The UUID representing a specific push. Format: `uuid` - **`alerting_sends`** `integer` The number of alerting sends. - **`app_key`** `string` The app key for the given push. - **`created`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when the push was created. Format: `date-time` Read only: true - **`direct_responses`** `integer` The number of direct responses. - **`influenced_responses`** `integer` The total number of influenced responses. - **`platforms`** `object` **OBJECT PROPERTIES** - **`amazon`** `object` **OBJECT PROPERTIES** - **`direct_responses`** `integer` The number of direct responses (clicks/app opens) to the notification on this platform as measured by the SDK. - **`influenced_responses`** `integer` The number of opens or clicks resulting from your notification (directly or indirectly). - **`sends`** `integer` The total number of audience members accounted on the specified platform. - **`android`** `object` **OBJECT PROPERTIES** - **`direct_responses`** `integer` The number of direct responses (clicks/app opens) to the notification on this platform as measured by the SDK. - **`influenced_responses`** `integer` The number of opens or clicks resulting from your notification (directly or indirectly). - **`sends`** `integer` The total number of audience members accounted on the specified platform. - **`ios`** `object` **OBJECT PROPERTIES** - **`direct_responses`** `integer` The number of direct responses (clicks/app opens) to the notification on this platform as measured by the SDK. - **`influenced_responses`** `integer` The number of opens or clicks resulting from your notification (directly or indirectly). - **`sends`** `integer` The total number of audience members accounted on the specified platform. - **`web`** `object` **OBJECT PROPERTIES** - **`direct_responses`** `integer` The number of direct responses (clicks/app opens) to the notification on this platform as measured by the SDK. - **`influenced_responses`** `integer` The number of opens or clicks resulting from your notification (directly or indirectly). - **`sends`** `integer` The total number of audience members accounted on the specified platform. - **`rich_deletions`** `integer` The number of rich deletions. - **`rich_responses`** `integer` The number of rich responses. - **`rich_sends`** `integer` The number of rich sends. - **`sends`** `integer` The number of pushes sent. - **`silent_sends`** `integer` The number of silent sends. **Examples** *Example* ```http GET /api/reports/perpush/detail/57ef3728-79dc-46b1-a6b9-20081e561f97 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/json { "app_key": "some_app_key", "push_id": "57ef3728-79dc-46b1-a6b9-20081e561f97", "created": "2023-07-25 23:03:12", "rich_deletions": 0, "rich_responses": 0, "rich_sends": 0, "sends": 103, "alerting_sends": 103, "silent_sends": 0, "direct_responses": 0, "influenced_responses": 3, "platforms": { "android": { "direct_responses": 0, "influenced_responses": 0, "sends": 22 }, "ios": { "direct_responses": 0, "influenced_responses": 1, "sends": 36 }, "amazon": { "direct_responses": 0, "influenced_responses": 1, "sends": 5 }, "web": { "direct_responses": 0, "influenced_responses": 1, "sends": 40 } } } ``` --- ## Per push time series report {#getperpushtimeseriesreport} Returns the default time series data (hourly precision for 12 hours) for a given push message. The series begins with the hour in which the push was sent. By specifying the precision without providing a time range, the default number of periods at each precision returned are as follows: Hourly: 12, Daily: 7, Monthly: 3. Results paginate if requesting narrow precision over a long period of time. [Jump to examples ↓](#getperpushtimeseriesreport-examples) ### `GET /api/reports/perpush/series/{push_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `push_id` | `string` | Required | The `push_id` of the requested report. | **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `precision` | `string` | | The precision of the report. Defaults to `HOURLY`. Possible values: `HOURLY`, `DAILY`, `MONTHLY` | | `start` | `string` | | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for start of report. | | `end` | `string` | | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for end of report. | **Responses** **`200`** Returned on success. Response body: **Content-Type:** `application/json;` **All of:** - **`push_id`** `string` The UUID representing a specific push. Format: `uuid` - **`app_key`** `string` The app key for the application. Example: `your_app_key` - **`end`** `string` The end [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for the report. Format: `date-time` Example: `2018-06-02 10:00:00` - **`precision`** `string` The precision of the report. Possible values: `HOURLY`, `DAILY`, `MONTHLY` Example: `HOURLY` - **`start`** `string` The start [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for the report. Format: `date-time` Example: `2018-06-01 10:00:00` - **`counts`** `array[object]` Array of total count objects, each representing counts within the given [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) range and precision. **Examples** *Example (response truncated to 2 items)* ```http GET /api/reports/perpush/series/57ef3728-79dc-46b1-a6b9-20081e561f97 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/json { "app_key": "some_app_key", "push_id": "57ef3728-79dc-46b1-a6b9-20081e561f97", "start": "2023-07-25 23:00:00", "end": "2023-07-26 11:00:00", "precision": "HOURLY", "counts": [ { "push_platforms": { "all": { "direct_responses": 0, "influenced_responses": 1, "sends": 58 }, "android": { "direct_responses": 0, "influenced_responses": 0, "sends": 22 }, "ios": { "direct_responses": 0, "influenced_responses": 1, "sends": 36 } }, "rich_push_platforms": { "all": { "responses": 0, "sends": 0 } }, "time": "2023-07-25 23:00:00" }, { "push_platforms": { "all": { "direct_responses": 0, "influenced_responses": 0, "sends": 0 }, "android": { "direct_responses": 0, "influenced_responses": 0, "sends": 0 }, "ios": { "direct_responses": 0, "influenced_responses": 0, "sends": 0 } }, "rich_push_platforms": { "all": { "responses": 0, "sends": 0 } }, "time": "2023-07-26 00:00:00" } ] } ``` --- ## Push body per push {#getpushbodyperpush} Returns the push body for the given push message. [Jump to examples ↓](#getpushbodyperpush-examples) ### `GET /api/reports/perpush/pushbody/{push_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `push_id` | `string` | Required | The `push_id` of the requested push body. | **Responses** **`200`** Returned on success. Response body: **Content-Type:** `application/json;` - **`push_body`** `string` The push body as a base64 encoded JSON value. **Examples** *Example* ```http GET /api/reports/perpush/pushbody/57ef3728-79dc-46b1-a6b9-20081e561f97 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/json { "push_body": "" } ``` --- ## Push report {#getpushreport} Get the number of pushes you have sent within a specified time period. [Jump to examples ↓](#getpushreport-examples) ### `GET /api/reports/sends` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `start` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for start of report. | | `end` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for end of report. | | `precision` | `string` | Required | Granularity of results to return. Defaults to `DAILY`. Possible values: `HOURLY`, `DAILY`, `MONTHLY` Default: `DAILY` | **Responses** **`200`** Returned on success, with the JSON representation of the sends in the body of the response. Response body: **Content-Type:** `application/json;` - **`next_page`** `string` There might be more than one page of results for this listing. Follow this URL if it is present to the next batch of results. Format: `url` - **`sends`** `array[object]` An array of send objects. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/reports/sends?start=2020-05-01T10:00&end=2020-05-30T20:00&precision=MONTHLY HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "sends": [ { "android": 50, "date": "2020-05-01 00:00:00", "ios": 500 } ], "next_page": "https://go.urbanairship.com/api/reports/..." } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); PlatformStatsRequest request = PlatformStatsRequest.newRequest(PlatformStatsRequestType.SENDS) .setStart(DateTime.parse("2020-05-01T10:34:22Z")) .setEnd(DateTime.parse("2020-05-30T10:34:22Z")) .setPrecision(Precision.MONTHLY); Response response = client.execute(request); ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, PushList ) client = BasicAuthClient( key='', secret='' ) start_date = datetime(2020, 5, 1) end_date = datetime(2020, 5, 30) precision = 'MONTHLY' listing = PushList(airship=client, start_date=start_date, end_date=end_date, precision=precision) for resp in listing: print(resp.date, resp.android, resp.ios) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') listing = UA::PushList.new( client: airship, start_date: '2020/05/01', end_date: '2020/05/30', precision: 'MONTHLY' ) listing.each do |resp| puts(resp) end ``` --- ## Response listing {#getresponses} Get a listing of all pushes, plus basic response information, for a given time period. Start and end date times are required parameters. The time defaults to 00:00 UTC if not specified. [Jump to examples ↓](#getresponses-examples) ### `GET /api/reports/responses/list` {{< note >}} If you don't specify a `start` and `end` time, the system assumes 00:00 UTC, which will provide results through the previous day. Use timestamps to get results for a specific time period. If only using the date, set it in the future to ensure you will see the most recent listing. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `start` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for start of report. | | `end` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for end of report. | | `limit` | `integer` | | Number of results to return at one time (for pagination). Min: 1 | **Responses** **`200`** Returned on success, with the JSON representation of the listing in the body of the response. Response body: **Content-Type:** `application/json;` - **`next_page`** `string` There might be more than one page of results for this listing. Follow this URL if it is present to the next batch of results. Format: `url` - **`pushes`** `array[object]` An array of all pushes and its basic response information. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/reports/responses/list?start=2020-08-01T10:00&end=2020-08-15T10:00&limit=20 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "next_page": "https://go.urbanairship.com/api/reports/responses/list?start=2020-08-01+10%...", "pushes": [ { "push_uuid": "f4db3752-a982-4a2b-994e-7b5fd1c7f02f", "push_time": "2020-08-15 02:12:22", "push_type": "UNICAST_PUSH", "group_id": "4e768dc7-4ebc-4206-890a-60b5627763a7", "direct_responses": 0, "sends": 1, "open_channels_sends": { "platforms": [] } }, { "push_uuid": "5a4ade58-fbd3-43a2-ac3c-e834ee190151", "push_time": "2020-08-14 19:58:15", "push_type": "UNICAST_PUSH", "group_id": "c5664e1f-106e-4616-9820-7d9ecce8a3f3", "direct_responses": 1, "sends": 2, "open_channels_sends": { "platforms": [] } } ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); PushListingRequest request = PushListingRequest.newRequest() .setStart(DateTime.parse("2020-08-01T10:34:22Z")) .setEnd(DateTime.parse("2020-08-15T10:34:22Z")) .setLimit(20); Response response = client.execute(request); // Get the first item in an array of push info responses. You can use all of the getters // listed in the "Individual Push Response Statistics" section. PushInfoResponse pushInfo = response.getBody().get().getPushInfoList().get().get(0); ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, ResponseList ) client = BasicAuthClient( key='', secret='' ) start_date = datetime(2020, 8, 1) end_date = datetime(2020, 8, 15) for response in ResponseList(airship=client, start_date=start_date, end_date=end_date): print(response) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') response_list = UA::ResponseList.new( client: airship, start_date: '2020-08-01', end_date: '2020-08-30', limit: 20, push_id_start: 'start_id' ) response_list.each do |resp| puts(resp) end ``` --- ## Response report {#getresponsereport} Get the number of direct and influenced opens of your app. [Jump to examples ↓](#getresponsereport-examples) ### `GET /api/reports/responses` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `start` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for start of report. | | `end` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for end of report. | | `precision` | `string` | | Granularity of results to return. Defaults to `DAILY`. Possible values: `HOURLY`, `DAILY`, `MONTHLY` Default: `DAILY` | **Responses** **`200`** Returned on success, with the JSON representation of the responses in the body of the response. Response body: **Content-Type:** `application/json;` - **`next_page`** `string` There might be more than one page of results for this listing. Follow this URL if it is present to the next batch of results. Format: `url` - **`responses`** `array[object]` An array of response objects. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/reports/responses?start=2020-05-01T10:00&end=2020-05-30T10:00&precision=MONTHLY HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "next_page": "https://go.urbanairship.com/api/reports/...", "responses": [ { "android": { "direct": 25, "influenced": 118 }, "date": "2020-05-01 00:00:00", "ios": { "direct": 16, "influenced": 87 } } ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); ResponseReportRequest request = ResponseReportRequest .newRequest(DateTime.parse("2020-05-01T10:34:22Z"), DateTime.parse("2020-05-30T10:34:22Z"), Precision.MONTHLY); Response response = client.execute(request); ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, ResponseReportList ) client = BasicAuthClient( key='', secret='' ) start_date = datetime(2020, 5, 1) end_date = datetime(2020, 5, 30) for response in ResponseReportList(airship=client, start_date=start_date, end_date=end_date, precision='DAILY'): print(response) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') listing = UA::ResponseReportList.new( client: airship, start_date: '2020-05-01', end_date: '2020-05-30', precision: 'MONTHLY' ) listing.each do |resp| puts(resp) end ``` --- ## Time in app report {#gettimeinappreport} Get the average amount of time users have spent in your app within the specified time period. [Jump to examples ↓](#gettimeinappreport-examples) ### `GET /api/reports/timeinapp` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `start` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for start of report. | | `end` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for end of report. | | `precision` | `string` | Required | Granularity of results to return. Defaults to `DAILY`. Possible values: `HOURLY`, `DAILY`, `MONTHLY` Default: `DAILY` | **Responses** **`200`** Returned on success, with the JSON representation of the time in app in the body of the response. Response body: **Content-Type:** `application/json;` - **`next_page`** `string` There might be more than one page of results for this listing. Follow this URL if it is present to the next batch of results. Format: `url` - **`sends`** `array[object]` An array of TimeInApp objects. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/reports/timeinapp?start=2020-05-01T10:00&end=2020-05-15T20:00&precision=MONTHLY HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "timeinapp": [ { "android": 50, "date": "2020-05-01 00:00:00", "ios": 500 } ], "next_page": "https://go.urbanairship.com/api/reports/..." } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); PlatformStatsRequest request = PlatformStatsRequest.newRequest(PlatformStatsRequestType.TIME_IN_APP) .setStart(DateTime.parse("2020-05-01T10:34:22Z")) .setEnd(DateTime.parse("2020-05-15T10:34:22Z")) .setPrecision(Precision.MONTHLY); Response response = client.execute(request); ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, TimeInAppList ) client = BasicAuthClient( key='', secret='' ) start_date = datetime(2020, 5, 1) end_date = datetime(2020, 5, 15) precision = 'MONTHLY' listing = TimeInAppList(airship=client, start_date=start_date, end_date=end_date, precision=precision) for resp in listing: print(resp.date, resp.android, resp.ios) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') listing = UA::TimeInAppList.new( client: airship, start_date: '2020-05-01', end_date: '2020-05-30', precision: 'MONTHLY') listing.each do |time_in_app| puts(time_in_app) end ``` --- ## Web response report {#getwebresponsereport} Get the web interaction data for the given app key. Accepts a required start time and optional end time and precision parameters. [Jump to examples ↓](#getwebresponsereport-examples) ### `GET /api/reports/web/interaction` {{< note >}} If you don't specify an `end` time, the system assumes 00:00 UTC, which will provide results through the previous day. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): rpt **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `app_key` | `string` | Required | The app key for your web project. | | `start` | `string` | Required | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for start of report. | | `end` | `string` | | A [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for end of report. | | `precision` | `string` | | The precision of the report. Defaults to `HOURLY`. Possible values: `HOURLY`, `DAILY`, `MONTHLY` | **Responses** **`200`** Returned on success, with the JSON representation of the web data in the body of the response. Response body: **Content-Type:** `application/json;` **All of:** - **`app_key`** `string` The app key for the application. Example: `your_app_key` - **`end`** `string` The end [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for the report. Format: `date-time` Example: `2018-06-02 10:00:00` - **`precision`** `string` The precision of the report. Possible values: `HOURLY`, `DAILY`, `MONTHLY` Example: `HOURLY` - **`start`** `string` The start [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) for the report. Format: `date-time` Example: `2018-06-01 10:00:00` - **`total_counts`** `array[object]` Array of total count objects, each representing counts within the given [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) range and precision. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/reports/web/interaction?app_key=YOUR_APP_KEY&start=2020-05-01T10:00&end=2020-05-03T20:00&precision=HOURLY HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "app_key": "YOUR_APP_KEY", "end": "2020-05-03 00:00:00", "precision": "HOURLY", "start": "2020-05-01 00:00:00", "total_counts": [ {"counts": {"clicks": 36, "sessions": 55 }, "date": "2020-05-01 10:00:00"}, {"counts": {"clicks": 50, "sessions": 79 }, "date": "2020-05-01 11:00:00"}, {"..."}, {"..."}, {"counts": {"clicks": 67, "sessions": 75 }, "date": "2020-05-03 20:00:00"} ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); WebResponseReportRequest webResponseReportRequest = WebResponseReportRequest.newRequest("", DateTime.parse("2020-08-01T10:34:22Z")); Response response = client.execute(webResponseReportRequest); ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, WebResponseReport ) client = BasicAuthClient( key='', secret='' ) start_date = datetime(2020, 5, 1) end_date = datetime(2020, 5, 3) for web_response in WebResponseReport(airship=client, start_date=start_date, end_date=end_date, precision='DAILY'): print(web_response) ``` --- # Schedules > Schedule notifications. {{< important >}} The API prohibits batch sizes of larger than 1,000 for scheduled pushes, and batches of larger than 100 for push to local time scheduled pushes. {{< /important >}} ## Delete schedule {#deleteschedule} Delete a schedule resource, which will result in no more pushes being sent. If the resource is successfully deleted, the response does not include a body. [Jump to examples ↓](#deleteschedule-examples) ### `DELETE /api/schedules/{schedule_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): sch **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `schedule_id` | `string` | Required | The ID of a schedule. | **Responses** **`204`** An API request was successful, but there is no response body to return. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http DELETE /api/schedules/b384ca54-0a1d-9cb3-2dfd-ae5964630e66 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 204 No Content ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); ScheduleDeleteRequest request = ScheduleDeleteRequest.newRequest("b384ca54-0a1d-9cb3-2dfd-ae5964630e66"); Response response = client.execute(request); ``` ```python from urbanairship import BasicAuthClient, ScheduledPush client = BasicAuthClient( key='', secret='' ) schedule = ScheduledPush.from_url(client, 'https://go.urbanairship.com/api/schedules/b384ca54-0a1d-9cb3-2dfd-ae5964630e66') # Cancel schedule schedule.cancel() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') schedule = airship.create_scheduled_push schedule = UA::ScheduledPush.from_url(client: airship, url: 'https://go.urbanairship.com/api/schedules/b384ca54-0a1d-9cb3-2dfd-ae5964630e66') schedule.cancel ``` --- ## List a specific schedule {#getschedule} Fetch the current definition of a single schedule resource. Returns a single schedule object. [Jump to examples ↓](#getschedule-examples) ### `GET /api/schedules/{schedule_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): sch **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `schedule_id` | `string` | Required | The ID of a schedule. | **Responses** **`200`** Returned on success, with the JSON representation of the scheduled push in the body of the response. Response body: **Content-Type:** `application/json` [Schedule object]({{< ref "/developer/rest-api/ua/schemas/schedules/" >}}#scheduleobject) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/schedules/5cde3564-ead8-9743-63af-821e12337812 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "name": "I would like to subscribe to your newsletter", "schedule": { "scheduled_time": "2020-04-01T18:45:30" }, "push": { "audience": { "tag": [ "intriguing", "ideas" ] }, "notification": { "alert": "Check your inbox!" }, "device_types": [ "ios", "android" ] } } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); ScheduleListingRequest request = ScheduleListingRequest.newRequest("5cde3564-ead8-9743-63af-821e12337812"); Response response = client.execute(request); SchedulePayloadResponse schedule = response.getBody().get().getSchedules().get(0); // Get the schedule's name Optional name = schedule.getName(); // Get the push IDs Set pushIds = schedule.getPushIds(); // Get the scheduled time Schedule sched = schedule.getSchedule(); // Get the associated push payload PushPayload payload = schedule.getPushPayload(); // Get the URL Optional url = schedule.getUrl(); ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') schedule = airship.create_scheduled_push scheduled_push = UA::ScheduledPush.new(airship) schedule_details = scheduled_push.list(schedule_id: '5cde3564-ead8-9743-63af-821e12337812') puts(schedule_details) ``` --- ## List schedules {#getschedules} List all existing schedules. Returns an array of schedule objects in the `schedules` attribute. [Jump to examples ↓](#getschedules-examples) ### `GET /api/schedules` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): sch **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `start` | `string` | | An optional string ID of the starting element for paginating results. | | `limit` | `integer` | | An optional integer as maximum number of elements to return. The default limit is 200 Schedule Objects per request. Set the limit to 200 or fewer in your API calls. | **Responses** **`200`** Returned on success, with the JSON representation of the scheduled pushes in the body of the response. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`count`** `integer` - **`next_page`** `string` There might be more than one page of results for this listing. Follow this URL if it is present to the next batch of results. Format: `url` Example: `https://go.urbanairship.com/api/schedules/?start=8bcb15a6-1f81-451a-95a1-05afd40e271c&limit=20` - **`ok`** `boolean` Success. - **`schedules`** `array` <[Schedule object]({{< ref "/developer/rest-api/ua/schemas/schedules/" >}}#scheduleobject)> An array of schedule objects. - **`total_count`** `integer` **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/schedules HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Count: 2 Data-Attribute: schedules Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "count": 2, "total_count": 4, "next_page": "https://go.urbanairship.com/api/schedules/?start=5c69320c-3e91-5241-fad3-248269eed104&limit=2&order=asc", "schedules": [ { "url": "http://go.urbanairship/api/schedules/2d69320c-3c91-5241-fac4-248269eed109", "schedule": { }, "push": { } }, { "url": "http://go.urbanairship/api/schedules/2d69320c-3c91-5241-fac4-248269eed10A", "schedule": { }, "push": { } } ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); ScheduleListingRequest request = ScheduleListingRequest.newRequest(); Response response = client.execute(request); List schedules = response.getBody().get().getSchedules(); ``` ```python from urbanairship import BasicAuthClient, ScheduledList client = BasicAuthClient( key='', secret='' ) for schedule in ScheduledList(client): print( schedule.name, schedule.url, schedule.push_ids, schedule.schedule, schedule.push ) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') scheduled_push_list = UA::ScheduledPushList.new(client: airship) scheduled_push_list.each do |schedule| puts(schedule) end ``` --- ## Pause a schedule {#pauseschedule} Pause a recurring scheduled message, preventing Airship from sending messages on a recurring scheduled message interval. Use the `/resume` endpoint to resume a schedule. The pause operation cannot be completed for recurring schedules that have schedule end times in the past. [Jump to examples ↓](#pauseschedule-examples) ### `POST /api/schedules/{schedule_id}/pause` {{< note >}} Paused schedules bear a `"paused": true` boolean. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): sch **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `schedule_id` | `string` | Required | The ID of the schedule you want to pause. | **Request body** A pause request is empty. **Content-Type:** `application/json` Type: `object` **Responses** **`204`** An API request was successful, but there is no response body to return. **`400`** Returned if the schedule end time for a recurring schedule is in the past. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`500`** Occurs if a schedule fails to pause. The error includes a list of `failed_triggers`, detailing the schedule triggers that caused this operation to fail. Response body: **Content-Type:** `application/json` - **`error`** `string` A description of the error. - **`error_code`** `integer` An error code representing the HTTP status and a more specific Airship error, if known. Default: `500` Example: `500` - **`failed_triggers`** `array[object]` - **`ok`** `boolean` If false, an error occurred. **Examples** *Example* ```http POST /api/schedules/5cde3564-ead8-9743-63af-821e12337812/pause HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```python from urbanairship import BasicAuthClient, ScheduledPush client = BasicAuthClient( key='', secret='' ) sched = ScheduledPush(client) sched.url = "http://go.urbanairship/api/schedules/5cde3564-ead8-9743-63af-821e12337812" sched.pause() ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); ScheduleStatusRequest pauseRequest = ScheduleStatusRequest.pauseScheduleRequest("68b2d71f-1c10-4592-bd96-2725aee0ae57"); Response pauseResponse = client.execute(pauseRequest); ``` --- ## Resume a schedule {#resumeschedule} Resume a recurring schedule that you previously paused, beginning with the next scheduled interval. The resume operation cannot be completed for recurring schedules that have schedule end times in the past. [Jump to examples ↓](#resumeschedule-examples) ### `POST /api/schedules/{schedule_id}/resume` {{< note >}} Paused schedules bear a `"paused": true` boolean. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): sch **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `schedule_id` | `string` | Required | The ID of the schedule you want to resume. | **Request body** A resume request is empty. **Content-Type:** `application/json` Type: `object` **Responses** **`204`** An API request was successful, but there is no response body to return. **`400`** Returned if the schedule end time is in the past. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`500`** Occurs if a schedule fails to resume. The error includes a list of `failed_triggers`, detailing the specific schedule IDs that caused the operation to fail. Response body: **Content-Type:** `application/json` - **`error`** `string` A description of the error. - **`error_code`** `integer` An error code representing the HTTP status and a more specific Airship error, if known. Default: `500` Example: `500` - **`failed_triggers`** `array[object]` - **`ok`** `boolean` If false, an error occurred. **Examples** *Example* ```http POST /api/schedules/5cde3564-ead8-9743-63af-821e12337812/resume HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```python from urbanairship import BasicAuthClient, ScheduledPush client = BasicAuthClient( key='', secret='' ) sched = ScheduledPush(client) sched.url = "http://go.urbanairship/api/schedules/5cde3564-ead8-9743-63af-821e12337812" sched.resume() ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); ScheduleStatusRequest resumeRequest = ScheduleStatusRequest.resumeScheduleRequest("68b2d71f-1c10-4592-bd96-2725aee0ae57"); Response resumeResponse = client.execute(resumeRequest); ``` --- ## Schedule a notification {#schedulenotification} Scheduled notifications are created by POSTing to the schedule URI. The body of the request must be one of a single [schedule object](/docs/developer/rest-api/ua/schemas/schedules/#scheduleobject) or an array of one or more schedule objects. [Jump to examples ↓](#schedulenotification-examples) ### `POST /api/schedules` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): psh **Request body** A single schedule object or an array of schedule objects. For Local Time Delivery, include no more than 100 Schedule Objects in your batch request. **Content-Type:** `application/json` **One of:** - `array` - [Schedule object]({{< ref "/developer/rest-api/ua/schemas/schedules/" >}}#scheduleobject) A schedule object consists of a schedule, i.e., a future delivery time, an optional name, and a push object. **Responses** **`201`** The response body will contain an array of response objects with the created resource URIs. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` Success. - **`operation_id`** `string` A unique string which identifies a single API call, and can be used to group multiple entities or side effects as related, in reporting and troubleshooting logs. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`schedule_ids`** `array[string]` An array of schedule IDs, each string uniquely identifying a schedule. Min items: 1, Max items: 100 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` - **`schedule_urls`** `array[string]` An array of schedule URLs. Min items: 0, Max items: 100 - **`schedules`** `array` <[Schedule object]({{< ref "/developer/rest-api/ua/schemas/schedules/" >}}#scheduleobject)> An array of schedule objects. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`413`** Returned when the request is too large to be processed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/schedules HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json [ { "name": "Morning People", "schedule": { "scheduled_time": "2020-06-03T09:15:00" }, "push": { "audience": { "tag": "earlyBirds" }, "notification": { "alert": "Good Day Sunshine" }, "device_types": [ "ios", "android" ] } }, { "name": "Everybody Else", "schedule": { "best_time": { "send_date": "2020-06-03" } }, "push": { "audience": { "tag": "normalPeople" }, "notification": { "alert": "Stay Up Late" }, "device_types": [ "ios", "android" ] } } ] ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); SchedulePayload schedulePayload = SchedulePayload.newBuilder() .setName("Morning People") .setSchedule(Schedule.newBuilder() .setScheduledTimestamp(DateTime.parse("2020-06-03T09:15:00Z")) .build()) .setPushPayload(PushPayload.newBuilder() .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS, DeviceType.ANDROID)) .setNotification(Notifications.alert("Good Day Sunshine")) .setAudience(Selectors.tag("earlyBirds")) .build()) .build(); ScheduleRequest scheduleRequest = ScheduleRequest.newRequest(schedulePayload); Response response = client.execute(scheduleRequest); ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, ScheduledPush, Push, tag, notification, scheduled_time ) client = BasicAuthClient( key='', secret='' ) # Create the push payload push = Push(client) push.audience = tag('earlyBirds') push.notification = notification(alert='Good Day Sunshine') push.device_types = ['ios', 'android'] # Create the schedule sched = ScheduledPush(client) sched.name = 'Morning People' sched.schedule = scheduled_time(datetime(2020, 6, 3, 9, 15, 0)) sched.push = push # Send the scheduled push response = sched.send() print('Created schedule. URL:', response.schedule_url) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') push = airship.create_push push.audience = UA.tag('earlyBirds') push.notification = UA.notification(alert: 'Morning People') push.device_types = UA.device_types(['ios','android']) schedule = airship.create_scheduled_push schedule.push = push schedule.name = "Morning People" schedule.schedule = UA.scheduled_time(Time.now.utc + 60) response = schedule.send_push print ("Created schedule. url: " + response.schedule_url) ``` *Example schedule with localizations* ```http POST /api/schedules HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json [ { "name": "Greetings", "schedule": { "best_time": { "send_date": "2020-11-15" } }, "push": { "device_types": [ "ios", "android" ], "audience": { "tag": "needs_a_greeting", "group": "new_customer" }, "notification": { "alert": "Hi!" }, "localizations": [ { "language": "de", "country": "AT", "notification": { "alert": "Grüss Gott" } }, { "language": "de", "country": "DE", "notification": { "alert": "Guten Tag" } } ] } } ] ``` ```http HTTP/1.1 201 Created Data-Attribute: schedule_urls Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "efb18e92-9a60-6689-45c2-82fedab36399", "schedule_urls": [ "https://go.urbanairship.com/api/schedules/eac2ace6-349a-41a2-b874-5496d7bf0100", "https://go.urbanairship.com/api/schedules/6c7c9bf5-cb2b-47cb-b27f-f85981391c4e" ], "schedule_ids": [ "eac2ace6-349a-41a2-b874-5496d7bf0100", "6c7c9bf5-cb2b-47cb-b27f-f85981391c4e" ], "schedules": [ { "url": "https://go.urbanairship.com/api/schedules/eac2ace6-349a-41a2-b874-5496d7bf0100", "schedule": { "scheduled_time": "2020-06-03T09:15:00" }, "name": "Morning People", "push": { "audience": { "tag": "earlyBirds" }, "notification": { "alert": "Good Day Sunshine" }, "device_types": [ "ios", "android" ] }, "push_ids": [ "83046227-9b06-4114-9f23-0df349792bbd" ] } { "url": "https://go.urbanairship.com/api/schedules/6c7c9bf5-cb2b-47cb-b27f-f85981391c4e", "schedule": { "best_time": { "send_date": "2020-06-03" } }, "name": "Everybody Else", "push": { "audience": { "tag": "normalPeople" }, "notification": { "alert": "Stay Up Late" }, "device_types": [ "ios", "android" ] }, "push_ids": [ "8438e81-bb31-82a9-5feb-e7fd5b21ca7e" ] } ] } ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, ScheduledPush, Push, tag_group, notification, best_time, localization ) client = BasicAuthClient( key='', secret='' ) # Create the push payload push = Push(client) push.audience = tag_group('new_customer', 'needs_a_greeting') push.notification = notification(alert='Hi!') push.device_types = ['ios', 'android'] push.localizations = [ localization( country='AT', language='de', notification=notification(alert='Grüss Gott') ), localization( country='DE', language='de', notification=notification(alert='Guten Tag') ) ] # Create the schedule sched = ScheduledPush(client) sched.name = 'Greetings' sched.schedule = best_time(send_date=datetime(2020, 11, 15)) sched.push = push # Send the scheduled push response = sched.send() print('Created schedule. URL:', response.schedule_url) ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); Localization one = Localization.newBuilder() .setCountry("AT") .setLanguage("de") .setNotification(Notifications.alert("Grüss Gott")) .build(); Localization two = Localization.newBuilder() .setCountry("DE") .setLanguage("de") .setNotification(Notifications.alert("Guten Tag")) .build(); SchedulePayload schedulePayload = SchedulePayload.newBuilder() .setName("Greetings") .setSchedule(Schedule.newBuilder() .setBestTime(BestTime.newBuilder() .setSendDate(DateTime.parse("2020-11-15T00:00:00Z")) .build()) .build()) .setPushPayload(PushPayload.newBuilder() .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS, DeviceType.ANDROID)) .setNotification(Notifications.alert("Hi!")) .setAudience(Selectors.tagWithGroup("needs_a_greeting", "new_customer")) .addLocalization(one) .addLocalization(two) .build()) .build(); ScheduleRequest scheduleRequest = ScheduleRequest.newRequest(schedulePayload); Response response = client.execute(scheduleRequest); ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') push = airship.create_push push.audience = UA.tag('needs_a_greeting', group:'new_customer') push.notification = UA.notification(alert: 'Hi!') push.device_types = UA.device_types(['ios', 'android']) push.localizations = { "language": "de", "country": "AT", "notification": { "alert": "Grüss Gott" } } schedule = airship.create_scheduled_push schedule.push = push schedule.name = "Greetings" schedule.schedule = UA.scheduled_time(Time.now.utc + 60) response = schedule.send_push print ("Created schedule. url: " + response.schedule_url) ``` --- ## Update schedule {#updateschedule} Update the state of a single schedule resource. The body must contain a single schedule object. A PUT cannot be used to create a new schedule; it can only be used to update an existing one. A push to local time schedule cannot be updated once it has begun sending pushes to a time zone. [Jump to examples ↓](#updateschedule-examples) ### `PUT /api/schedules/{schedule_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): sch **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `schedule_id` | `string` | Required | The ID of a schedule. | **Request body** A single schedule object. **Content-Type:** `application/json` [Schedule object]({{< ref "/developer/rest-api/ua/schemas/schedules/" >}}#scheduleobject) **Responses** **`200`** Returned if the scheduled push has been successfully updated. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` Success. - **`operation_id`** `string` A unique string which identifies a single API call, and can be used to group multiple entities or side effects as related, in reporting and troubleshooting logs. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`schedule_urls`** `array[string]` An array of schedule URLs. Min items: 0, Max items: 100 Example: `https://go.urbanairship/api/schedules/2d69320c-3c91-5241-fac4-248269eed109` - **`schedules`** `array` <[Schedule object]({{< ref "/developer/rest-api/ua/schemas/schedules/" >}}#scheduleobject)> An array of schedule objects. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`409`** Returned if the local time scheduled push is in progress. **`413`** Returned when the request is too large to be processed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http PUT /api/schedules/5cde3564-ead8-9743-63af-821e12337812 HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "name": "I would like to subscribe to your newsletter", "schedule": { "scheduled_time": "2020-04-01T18:45:30" }, "push": { "audience": { "tag": [ "intriguing", "ideas", "thought_leadership" ] }, "notification": { "alert": "Check your inbox!" }, "device_types": [ "ios", "android" ] } } ``` ```http HTTP/1.1 200 OK Content-Length: 123 Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "7c56d013-5599-d66d-6086-6205115d85e2", "schedule_urls": [ "https://go.urbanairship.com/api/schedules/0af1dead-e769-4b78-879a-7c4bb52d7c9e" ], "schedules": [ { "url": "https://go.urbanairship.com/api/schedules/0af1dead-e769-4b78-879a-7c4bb52d7c9e", "schedule": { "scheduled_time": "2020-04-01T18:45:30" }, "name": "I would like to subscribe to your newsletter", "push": { "audience": {"tag": ["intriguing", "ideas", "thought_leadership"] }, "notification": {"alert": "Check your inbox!"}, "device_types": [ "ios", "android" ] }, "push_ids": [ "48fb8e8a-ee51-4e2a-9a47-9fab9b13d846" ] } ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); SchedulePayload schedulePayload = SchedulePayload.newBuilder() .setName("I would like to subscribe to your newsletter") .setSchedule(Schedule.newBuilder() .setScheduledTimestamp(DateTime.parse("2020-04-01T18:45:00Z")) .build()) .setPushPayload(PushPayload.newBuilder() .setDeviceTypes(DeviceTypeData.of(DeviceType.IOS, DeviceType.ANDROID)) .setNotification(Notifications.alert("Check your inbox!")) .setAudience(Selectors.tag("intriguing")) .build()) .build(); ScheduleRequest scheduleRequest = ScheduleRequest.newUpdateRequest(schedulePayload, "5cde3564-ead8-9743-63af-821e12337812"); Response response = client.execute(scheduleRequest); ``` ```python from datetime import datetime from urbanairship import ( BasicAuthClient, ScheduledPush, Push, tag, notification, scheduled_time ) client = BasicAuthClient( key='', secret='' ) schedule = ua.ScheduledPush.from_url(client, 'https://go.urbanairship.com/api/schedules/5cde3564-ead8-9743-63af-821e12337812') # change scheduled time to tomorrow schedule.schedule = scheduled_time(datetime.datetime.utcnow() + datetime.timedelta(days=1)) resp = schedule.update() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') schedule = airship.create_scheduled_push schedule = UA::ScheduledPush.from_url(client: airship, url: 'https://go.urbanairship.com/api/schedules/5cde3564-ead8-9743-63af-821e12337812') # change scheduled time to tomorrow schedule.schedule = UA.scheduled_time(Time.now.utc + (60 * 60 * 24)) schedule.update ``` --- # Segments > Segments are portions of your audience that have arbitrary metadata (e.g., tags, location data, etc.) attached. You can create, delete, update, or request information on a Segment via the `/api/segments/` endpoint. Pushing to a Segment is done through the `/api/push/` endpoint. See the [Audience selection](/developer/rest-api/ua/schemas/audience-selection/) section for more information. ## Create Segment {#createsegment} Create a new Segment. [Jump to examples ↓](#createsegment-examples) ### `POST /api/segments` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) **Request body** A single Segment object. **Content-Type:** `application/json` - **`criteria`** `object` **REQUIRED** Defines the set of devices to send notifications to. `criteria` is a JSON expression containing the same information as the audience selector, including [Event Segmentation](/docs/developer/rest-api/ua/schemas/event-segmentation/). See [Audience selection](/docs/developer/rest-api/ua/schemas/audience-selection/) for more information. **One of:** - [Compound selector]({{< ref "/developer/rest-api/ua/schemas/audience-selection/" >}}#compoundselector) Compound selectors combine boolean operators (AND, OR, or NOT) with atomic or nested compound selectors. - [Atomic selector]({{< ref "/developer/rest-api/ua/schemas/audience-selection/" >}}#atomicselector) Atomic selectors are the simplest way to identify a single device, i.e., app or browser installation, or a group of devices. These selectors are either a unique identifier for the device such as a Channel ID or metadata that maps to the device (or multiple devices) such as a tag. - **`display_name`** `string` **REQUIRED** Human readable name for this Segment. This will be used in the dashboard. Example: `News but not sports` **Responses** **`201`** The Segment was created. Response headers: | Name | Type | Description | |------|------|-------------| | `Location` | `string` | The newly created Segment. | Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` If true, the operation completed successfully and returns expected results. - **`operation_id`** `string` A unique string identifying an API call, and can be used to identify operations in reporting and troubleshooting logs. Format: `uuid` Example: `ef625038-70a3-41f1-826f-57bc11dd625a` - **`segment_id`** `string` The ID of the newly created Segment. Format: `uuid` Example: `1d154121-951f-45b9-896d-e70718b5865b` **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/segments HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "display_name": "News but not sports", "criteria": { "and": [ {"tag": "news"}, {"not": {"tag": "sports"} } ] } } ``` ```http HTTP/1.1 201 Created Location: https://go.urbanairship.com/api/segments/f35da41d-59c1-4106-a192-9594bd480cb6 Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "segment_id": "f35da41d-59c1-4106-a192-9594bd480cb6", "operation_id": "1d154121-951f-45b9-896d-e70718b5865b" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); // Define the segment criteria Selector compound = Selectors.and(Selectors.tag("news"), Selectors.not(Selectors.tag("sports"))); SegmentRequest request = SegmentRequest.newRequest(); request.setCriteria(compound); request.setDisplayName("News but not sports"); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, Segment, tag, not_, and_ ) client = BasicAuthClient( key='', secret='' ) # Create a new segment segment = Segment() segment.display_name = "News but not sports" segment.criteria = and_( tag('news'), not_(tag('sports')) ) # Create the segment response = segment.create(client) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') segment = UA::Segment.new(client: airship) segment.display_name = 'Display Name' segment.criteria = { 'tag' => 'existing_tag' } segment.create ``` --- ## Delete Segment {#deletesegment} Remove the Segment. [Jump to examples ↓](#deletesegment-examples) ### `DELETE /api/segments/{segment_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `segment_id` | `string` | Required | The Segment you want to retrieve. | **Responses** **`204`** An API request was successful, but there is no response body to return. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http DELETE /api/segments/00c0d899-a595-4c66-9071-bc59374bbe6b HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 204 No Content ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); SegmentDeleteRequest request = SegmentDeleteRequest.newRequest("00c0d899-a595-4c66-9071-bc59374bbe6b"); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, Segment ) client = BasicAuthClient( key='', secret='' ) # Delete a segment segment = Segment() segment.from_id(client, "00c0d899-a595-4c66-9071-bc59374bbe6b") response = segment.delete(client) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') segment = UA::Segment.new(client: airship) segment.from_id(id: '00c0d899-a595-4c66-9071-bc59374bbe6b') segment.delete ``` --- ## Segment listing {#getsegments} List all segments for the application. [Jump to examples ↓](#getsegments-examples) ### `GET /api/segments` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) **Query parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `limit` | `integer` | | Set the limit to 200 or fewer Segment objects per request. Max: 200 | **Responses** **`200`** Returned on success a JSON object containing segments. Response headers: | Name | Type | Description | |------|------|-------------| | `Link` | `string` | A link to the next page of results. If present, follow this URL to the next page of segments. Also available in the `next_page` value in the response body. | Response body: **Content-Type:** `application/json` - **`next_page`** `string` An optional relative URL which can be used to retrieve the next page of results. If no more results are available, next_page will be absent. - **`segments`** `array[object]` **REQUIRED** An array of segments for the application. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/segments/ HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Link: ;rel=next Content-Type: application/vnd.urbanairship+json; version=3 { "next_page": "https://go.urbanairship.com/api/segments?limit=1&sort=id&order=asc&start=3832cf72-cb44-4132-a11f-eafb41b82f64", "segments": [ { "creation_date": 1346248822221, "display_name": "A segment", "id": "00c0d899-a595-4c66-9071-bc59374bbe6b", "modification_date": 1346248822221 } ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); SegmentListingRequest request = SegmentListingRequest.newRequest(); Response response = client.execute(request); // Get the first segment in the list SegmentListingView segment = response.getBody().get().getSegmentListingViews().get(0); // Get the segment display name String displayName = segment.getDisplayName(); // Get the segment ID String id = segment.getSegmentId(); ``` ```python from urbanairship import ( BasicAuthClient, SegmentList ) client = BasicAuthClient( key='', secret='' ) # List all segments segment_list = SegmentList(client) for segment in segment_list: print(segment.display_name) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') segment_list = UA::SegmentList.new(client: airship) segment_list.each do |segment| puts(segment['display_name']) end ``` --- ## Segment lookup {#getsegment} Lookup a Segment. [Jump to examples ↓](#getsegment-examples) ### `GET /api/segments/{segment_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `segment_id` | `string` | Required | The Segment you want to retrieve. | **Responses** **`200`** Returns OK for success. Response body: **Content-Type:** `application/json` - **`criteria`** `object` **REQUIRED** Defines the set of devices to send notifications to. `criteria` is a JSON expression containing the same information as the audience selector, including [Event Segmentation](/docs/developer/rest-api/ua/schemas/event-segmentation/). See [Audience selection](/docs/developer/rest-api/ua/schemas/audience-selection/) for more information. **One of:** - [Compound selector]({{< ref "/developer/rest-api/ua/schemas/audience-selection/" >}}#compoundselector) Compound selectors combine boolean operators (AND, OR, or NOT) with atomic or nested compound selectors. - [Atomic selector]({{< ref "/developer/rest-api/ua/schemas/audience-selection/" >}}#atomicselector) Atomic selectors are the simplest way to identify a single device, i.e., app or browser installation, or a group of devices. These selectors are either a unique identifier for the device such as a Channel ID or metadata that maps to the device (or multiple devices) such as a tag. - **`display_name`** `string` **REQUIRED** Human readable name for this Segment. This will be used in the dashboard. Example: `News but not sports` **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/segments/00c0d899-a595-4c66-9071-bc59374bbe6b HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "criteria": { "and": [ { "tag": "ipad" }, { "not": { "tag": "foo" } } ] }, "display_name": "A segment" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); SegmentLookupRequest request = SegmentLookupRequest.newRequest("00c0d899-a595-4c66-9071-bc59374bbe6b"); Response response = client.execute(request); // Get the segment criteria Selector criteria = response.getBody().get().getCriteria(); // Get the segment display name String displayName = response.getBody().get().getDisplayName(); ``` ```python from urbanairship import ( BasicAuthClient, Segment ) client = BasicAuthClient( key='', secret='' ) # Look up a segment by ID segment = Segment() response = segment.from_id(client, "00c0d899-a595-4c66-9071-bc59374bbe6b") ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') segment = UA::Segment.new(client: airship) details = segment.from_id(id: '00c0d899-a595-4c66-9071-bc59374bbe6b') ``` --- ## Update Segment {#updatesegment} Change the definition of the Segment. [Jump to examples ↓](#updatesegment-examples) ### `PUT /api/segments/{segment_id}` {{< note >}} Segmentation data is evaluated at send time. If you schedule a message that targets a Segment and then edit that Segment, the scheduled message automatically uses the updated Segment criteria. "Scheduled" includes recurring messages. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `segment_id` | `string` | Required | The Segment you want to retrieve. | **Request body** A single Segment object. **Content-Type:** `application/json` - **`criteria`** `object` **REQUIRED** Defines the set of devices to send notifications to. `criteria` is a JSON expression containing the same information as the audience selector, including [Event Segmentation](/docs/developer/rest-api/ua/schemas/event-segmentation/). See [Audience selection](/docs/developer/rest-api/ua/schemas/audience-selection/) for more information. **One of:** - [Compound selector]({{< ref "/developer/rest-api/ua/schemas/audience-selection/" >}}#compoundselector) Compound selectors combine boolean operators (AND, OR, or NOT) with atomic or nested compound selectors. - [Atomic selector]({{< ref "/developer/rest-api/ua/schemas/audience-selection/" >}}#atomicselector) Atomic selectors are the simplest way to identify a single device, i.e., app or browser installation, or a group of devices. These selectors are either a unique identifier for the device such as a Channel ID or metadata that maps to the device (or multiple devices) such as a tag. - **`display_name`** `string` **REQUIRED** Human readable name for this Segment. This will be used in the dashboard. Example: `News but not sports` **Responses** **`200`** Returned if the Segment has been successfully updated. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http PUT /api/segments/00c0d899-a595-4c66-9071-bc59374bbe6b HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "display_name": "Entertainment but not sports", "criteria": { "and": [ {"tag": "entertainment"}, {"not": {"tag": "sports"} } ] } } ``` ```http HTTP/1.1 200 OK Content-Length: 65 Content-Type: application/vnd.urbanairship+json;version=3 { "ok": true, "operation_id": "1f93ca85-b8fd-4833-8d1a-6e2b7f4ceea9" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); // Define the segment criteria Selector compound = Selectors.and(Selectors.tag("entertainment"), Selectors.not(Selectors.tag("sports"))); SegmentRequest request = SegmentRequest.newUpdateRequest("00c0d899-a595-4c66-9071-bc59374bbe6b"); request.setCriteria(compound); request.setDisplayName("Entertainment but not sports"); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, Segment, tag, not_, and_ ) client = BasicAuthClient( key='', secret='' ) # Update an existing segment segment = Segment() segment.from_id(client, "00c0d899-a595-4c66-9071-bc59374bbe6b") # Update segment properties segment.display_name = "Entertainment but not sports" segment.criteria = and_( tag('entertainment'), not_(tag('sports')) ) # Save the changes response = segment.update(client) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') segment = UA::Segment.new(client: airship) segment.from_id(id: '00c0d899-a595-4c66-9071-bc59374bbe6b') segment.display_name = 'New Display Name' segment.criteria = { 'tag' => 'new_tag' } segment.update ``` --- # SMS > Register and manage SMS channels. See [SMS Platform Information](/developer/api-integrations/sms/) to get started with SMS notifications. ## Custom SMS response {#createcustomsmsresponse} Respond to a mobile-originated message based on a keyword consumed by your custom-response webhook, using a mobile-originated ID. See [SMS Keyword Webhooks](/docs/developer/api-integrations/sms/inbound-message-handling/) for information about setting up a custom response webhook server. [Jump to examples ↓](#createcustomsmsresponse-examples) ### `POST /api/sms/custom-response` **Security:** - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) **Request headers:** | Name | Type | Required | Description | |------|------|----------|-------------| | `X-UA-Appkey` | `string` | Required | The application key for your project. | **Request body** **Content-Type:** `application/json` **One of:** - **`mobile_originated_id`** `string` **REQUIRED** The identifier that you received through your SMS webhook corresponding to the mobile-originated message that you're issuing a custom response to. The `mobile_originated_id` is valid for 10 minutes from the `received_timestamp` in the payload sent to your webhook server's `/inbound-sms` endpoint. Format: `uuid` - **`sms`** `object` **REQUIRED** **OBJECT PROPERTIES** - **`alert`** `string` **REQUIRED** Your custom SMS message. - **`shorten_links`** `boolean` If true, Airship will shorten HTTP/HTTPS links (space delimited) in the message text fields, producing unique, 25 character URLs for each member of your audience. Airship produces `short_link_click` events in the Real-Time Data Stream for each link that a user engages with. When this setting is enabled, you can add or remove tags from users who click your links by adding query strings to your URLs. You can serialize tag operations with `&`: * `?ua-tag-add=tag_group:tag&another_group:tag2` — adds a tag in `tag_group` to the `channel_id`. * `?ua-tag-remove=tag_group:tag&another_group:tag2` — removes a tag in `tag group` from the `channel_id`. * `?ua-list-add=subscription_list_id` — adds the user's channel to the `subscription list`. * `?ua-list-remove=subscription_list_id` — removes the user's channel from the `subscription list`. Default: `false` - **`mms`** `object` <[MMS platform overrides]({{< ref "/developer/rest-api/ua/schemas/platform-overrides/" >}}#mmsoverrideobject)> **REQUIRED** Provides the content for a push to MMS channels. If `sms` is in the `device_type` array, your request may include this object. It cannot be combined with an SMS Platform Override as a single push can only include either an SMS or MMS payload. - **`mobile_originated_id`** `string` **REQUIRED** The identifier that you received through your SMS webhook corresponding to the mobile-originated message that you're issuing a custom response to. The `mobile_originated_id` is valid for 10 minutes from the `received_timestamp` in the payload sent to your webhook server's `/inbound-sms` endpoint. Format: `uuid` **Responses** **`200`** The operation was successful. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` If `true`, your request was successful. - **`operation_id`** `string` A unique identifier for an operation; you can use this identifier to find the operation for troubleshooting purposes. Format: `uuid` - **`push_id`** `string` A unique identifier for a push operation. Format: `uuid` **`404`** The mobile_originated_id could not be found. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`error`** `string` A plain-text explanation of the error. - **`ok`** `boolean` If false, your request was unsuccessful. - **`operation_id`** `string` A unique identifier for an operation; you can use this identifier to find the operation for troubleshooting purposes. Format: `uuid` **Examples** *SMS example* ```http POST /api/sms/custom-response HTTP/1.1 Authorization: Bearer X-UA-Appkey: Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "sms" : { "alert": "Your balance is $1234.56. Go to https://www.example.com/myaccount/my-balance?ua-tag-add=balance_prefs:sms to see more about your account.", "shorten_links": true }, "mobile_originated_id" : "28883743-4868-4083-ab5d-77ac4542531a" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setBearerToken("") .build(); CustomSmsResponseSmsPayload customSmsResponseChannelSms = CustomSmsResponseSmsPayload.newBuilder() .setAlert("Your balance is $1234.56. Go to https://www.example.com/myaccount/my-balance?ua-tag-add=balance_prefs:sms to see more about your account.") .setMobileOriginatedId("28883743-4868-4083-ab5d-77ac4542531a") .setShortenLinks(true) .build(); CustomSmsResponseRequest customSmsResponseRequest = CustomSmsResponseRequest.newRequest(customSmsResponseChannelSms); Response response = client.execute(customSmsResponseRequest); ``` ```python from urbanairship import ( BearerTokenClient, SmsCustomResponse, sms, mms ) client = BearerTokenClient( app_key='', token='' ) custom_response = SmsCustomResponse( client=client, mobile_originated_id="28883743-4868-4083-ab5d-77ac4542531a" ) custom_response.sms = sms( alert="Your balance is $1234.56. Go to https://www.example.com/myaccount/my-balance?ua-tag-add=balance_prefs:sms to see more about your account.", shorten_links=True ) response = custom_response.send() ``` *MMS example* ```http POST /api/sms/custom-response HTTP/1.1 Authorization: Bearer X-UA-Appkey: Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "mms" : { "fallback_text": "See fun cat pics at https://example.com/cat/pics/12345678", "slides": [ { "media": { "url": "https://example.com/cat/pics/12345678.gif", "content_type": "image/gif", "content_length": 23098 } } ], "shorten_links": true }, "mobile_originated_id" : "3e1e4fb3-2d3c-431e-96bf-9b235a12f84b" } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "operation_id": "f3d0993e-e3e1-4aae-b1c0-864a715bfaff", "push_id": "7502abe6-e6ea-4f2b-906f-ebbab612c69e" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setBearerToken("") .build(); MmsSlides mmsSlides = MmsSlides.newBuilder() .setText("Test") .setMediaUrl("https://example.com/cat/pics/12345678.gif") .setMediaContentType("image/gif") .setMediaContentLength(23098) .build(); CustomSmsResponseMmsPayload customSmsResponseMmsPayload = CustomSmsResponseMmsPayload.newBuilder() .setFallbackText("See fun cat pics at https://example.com/cat/pics/12345678") .setMobileOriginatedId("28883743-4868-4083-ab5d-77ac4542531a") .setSlides(mmsSlides) .build(); CustomSmsResponseRequest customSmsResponseRequest = customSmsResponseRequest.newRequest(customSmsResponseMmsPayload); Response response = client.execute(customSmsResponseRequest); ``` ```python from urbanairship import ( BearerTokenClient, SmsCustomResponse, mms ) client = BearerTokenClient( app_key='', token='' ) custom_response = SmsCustomResponse( client=client, mobile_originated_id="3e1e4fb3-2d3c-431e-96bf-9b235a12f84b" ) custom_response.mms = mms( fallback_text="See fun cat pics at https://example.com/cat/pics/12345678", slides=[{ "media": { "url": "https://example.com/cat/pics/12345678.gif", "content_type": "image/gif", "content_length": 23098 } }], shorten_links=True ) response = custom_response.send() ``` --- ## Manually trigger a keyword interaction {#triggersmskeywordinteraction} Trigger Mobile Originated (MO) keyword interactions on behalf of an MSISDN. [Jump to examples ↓](#triggersmskeywordinteraction-examples) ### `POST /api/sms/{msisdn}/keywords` **Security:** - [basicAppAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAppAuth) - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `msisdn` | `string` | Required | The identifier for the SMS channel you want to trigger a mobile originated keyword from. | **Request headers:** | Name | Type | Required | Description | |------|------|----------|-------------| | `X-UA-Appkey` | `string` | Required | The application key for your project. | **Request body** **Content-Type:** `application/json` - **`keyword`** `string` **REQUIRED** The keyword you want to trigger an action for. Must be an alphanumeric string with no spaces. - **`sender_ids`** `array` <[Sender ID]({{< ref "/developer/rest-api/ua/schemas/others/" >}}#sender_id)> **REQUIRED** The [sender IDs](/docs/developer/rest-api/ua/schemas/others/#sender_id) with keyword actions that you want to test. Airship returns a 400 if the `keyword` is not configured for one or more of the senders in the array. Min items: 1 - **`timestamp`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) when the MO keyword was sent. If absent, Airship uses the server-time of your request. Format: `date-time` **Responses** **`200`** The operation was successful. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` If `true`, your request was successful. **`400`** The operation was not successful. If the request is formatted correctly, one or more `sender_ids` does not exist or the keyword is not configured for one or more of the `sender_ids`. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/sms/15035556789/keywords HTTP/1.1 User-Agent: Apache-HttpAsyncClient/4.0.1 (java 1.5) Content-Type: application/json Authorization: Basic Connection: close { "keyword" : "stop", "sender_ids" : [ "54321", "1234"] } ``` ```http HTTP/1.1 200 OK Content-Type: application/json { "ok": true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); KeywordInteractionRequest request = KeywordInteractionRequest.newRequest("15035556789") .addKeyword("stop") .addSenderId("54321") .addSenderId("1234"); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, KeywordInteraction ) from datetime import datetime client = BasicAuthClient( key='', secret='' ) interaction = KeywordInteraction( client=client, keyword="stop", sender_ids=["54321", "1234"], timestamp=datetime(2021, 10, 8, 12, 0, 0) ) response = interaction.post() ``` *Failure response (Keyword not configured for Sender ID)* ```http HTTP/1.1 400 Bad Request Content-Type: application/json { "ok" : false, "error" : "The following sender(s) are not configured for the 'stop' keyword: ['1234']", "error_code" : 400 } ``` --- ## Opt-out of SMS messages {#optoutsmschannel} This will mark an SMS channel as opted-out (inactive) and it will not receive alerts even when they are addressed in the future. To opt the user back in, call the registration function again with a valid `opted_in` value. [Jump to examples ↓](#optoutsmschannel-examples) ### `POST /api/channels/sms/opt-out` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** **Content-Type:** `application/json` - **`msisdn`** `string` **REQUIRED** The mobile phone number you want to opt-out of SMS messages. Must be numeric characters only, without leading zeros. 15 digits maximum. Max length: 15 - **`sender`** `string` **REQUIRED** A long or short code the app is configured to send from. For example, `12345`. **Responses** **`202`** The msisdn/channel is opted-out of SMS notifications. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` If true, the operation completed successfully. **`400`** The request body is not valid. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`details`** `object` **OBJECT PROPERTIES** - **`error`** `string` Specific error message that explains why the request was unsuccessful. - **`error`** `string` Returned with 40x responses; explains why the request was unsuccessful. - **`error_code`** `integer` The 5-digit Airship error code, pointing to a more specific error than the HTTP status. - **`ok`** `boolean` If false, the request was unsuccessful. **Examples** *Example* ```http POST /api/channels/sms/opt-out HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "sender": "12345", "msisdn": "15035556789" } ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); SmsRegistrationRequest request = SmsRegistrationRequest .newOptOutRequest("12345", "15035556789"); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, Sms ) client = BasicAuthClient( key='', secret='' ) sms = Sms( client=client, sender='12345', msisdn='15035556789' ) response = sms.opt_out() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') sms_channel = UA::Sms.new(client: airship) sms_channel.msisdn = '15035556789' sms_channel.sender = '12345' sms_channel.opt_out ``` --- ## Register SMS channel {#registersmschannel} Create an SMS channel. If the channel has not opted in yet (the request did not contain `opted_in`), Airship creates the channel with `opt_in` set to `false` and the user receives a message prompting them to complete the opt-in flow; you can assign tags and organize `pending` channels before the user has finished the opt-in process, but you cannot send messages to channels until they opt in to your audience. SMS notifications require a `sender` - a number that recipients will receive SMS notifications from. [Contact Airship Sales](https://www.airship.com/contact-us/) or your Account Manager to provision your project for SMS notifications and complete the configuration. [Jump to examples ↓](#registersmschannel-examples) ### `POST /api/channels/sms` {{< note >}} Avoid repeated registration attempts. Repeated registrations of the same MSISDN and sender without an `opted_in` value will result in multiple opt-in instruction messages being sent to the MSISDN. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** **Content-Type:** `application/json` - **`attributes`** `object` An optional object containing the customer-provided attributes associated with the SMS channel. - **`locale_country`** `string` The ISO 3166 two-character country code. The value for this field becomes a tag in the `ua_locale_country` tag group. - **`locale_language`** `string` The ISO 639-1 two-character language code. The value for this field becomes a tag in the `ua_locale_language` tag group. - **`msisdn`** `string` **REQUIRED** The mobile phone number you want to register as an SMS channel (or send a request to opt-in). Must be numeric characters only, without leading zeros. Max length: 15 - **`opted_in`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) that represents the date and time when explicit permission was received from the user to receive messages. Format: `date-time` - **`sender`** `string` **REQUIRED** A long or short code the app is configured to send from. For example, `12345`. - **`tag_operations`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Optionally one or more tag group objects associated with the SMS channel. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`timezone`** `string` The IANA identifier for a time zone, e.g., `America/Los_Angeles`. The value in this field becomes a tag in the `timezone` tag group. **Responses** **`200`** A channel with this msisdn/sender combination already exists. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` **One of:** - **`attributes`** `object` **OBJECT PROPERTIES** - **`ok`** `boolean` If `true`, the attributes were set correctly. - **`channel_id`** `string` Unique Channel ID for the SMS channel. Format: `uuid` - **`ok`** `boolean` If true, Airship creates a channel value with `opt_in` set to `true`. - **`operation_id`** `string` A unique identifier for an operation; you can use this identifier to find the operation for troubleshooting purposes. Format: `uuid` - **`tags`** `object` **OBJECT PROPERTIES** - **`ok`** `boolean` If `true`, the tags were set correctly. - **`attributes`** `object` **OBJECT PROPERTIES** - **`ok`** `boolean` If `true`, the attributes were set correctly. - **`channel_id`** `string` **REQUIRED** Unique Channel ID for the SMS channel. This channel is created with `opt_in` set to `false`, as the user has not yet opted in to your audience. Format: `uuid` - **`ok`** `boolean` **REQUIRED** If true, Airship creates a channel with `opt_in` set to `false` and Airship sends a message prompting the user to opt in to your audience. - **`operation_id`** `string` **REQUIRED** A unique identifier for an operation; you can use this identifier to find the operation for troubleshooting purposes. Format: `uuid` - **`push_id`** `string` **REQUIRED** Identifies the message prompting the user to opt in to your audience, sent as a result of a request without an `opted_in` value. Format: `uuid` - **`status`** `string` **REQUIRED** The channel has been created but has not yet opted-in. Possible values: `pending` - **`tags`** `object` **OBJECT PROPERTIES** - **`ok`** `boolean` If `true`, the tags were set correctly. **`201`** The channel was created. If the request did not contain an `opted_in` value, the channel is created with a `pending` status and the channel's `opt_in` value is set to `false`; you can assign assign tags and organize `pending` channels before the user has finished the opt-in process, but you cannot send messages to channels until they complete the opt-in flow. Response headers: | Name | Type | Description | |------|------|-------------| | `location` | `string` | URI of the channel, used for later registrations. | Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` **One of:** - **`attributes`** `object` **OBJECT PROPERTIES** - **`ok`** `boolean` If `true`, the attributes were set correctly. - **`channel_id`** `string` Unique Channel ID for the SMS channel. Format: `uuid` - **`ok`** `boolean` If true, Airship creates a channel value with `opt_in` set to `true`. - **`operation_id`** `string` A unique identifier for an operation; you can use this identifier to find the operation for troubleshooting purposes. Format: `uuid` - **`tags`** `object` **OBJECT PROPERTIES** - **`ok`** `boolean` If `true`, the tags were set correctly. - **`attributes`** `object` **OBJECT PROPERTIES** - **`ok`** `boolean` If `true`, the attributes were set correctly. - **`channel_id`** `string` **REQUIRED** Unique Channel ID for the SMS channel. This channel is created with `opt_in` set to `false`, as the user has not yet opted in to your audience. Format: `uuid` - **`ok`** `boolean` **REQUIRED** If true, Airship creates a channel with `opt_in` set to `false` and Airship sends a message prompting the user to opt in to your audience. - **`operation_id`** `string` **REQUIRED** A unique identifier for an operation; you can use this identifier to find the operation for troubleshooting purposes. Format: `uuid` - **`push_id`** `string` **REQUIRED** Identifies the message prompting the user to opt in to your audience, sent as a result of a request without an `opted_in` value. Format: `uuid` - **`status`** `string` **REQUIRED** The channel has been created but has not yet opted-in. Possible values: `pending` - **`tags`** `object` **OBJECT PROPERTIES** - **`ok`** `boolean` If `true`, the tags were set correctly. **`400`** The channel could not be created. This error occurs when the project is not configured with a valid sender, the request was missing required fields, or the MSISDN does not meet the E.164 international standard. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`errors`** `string` Returned with 40x responses; explains reason for the unsuccessful request. Example: `Unable to retrieve details for sender 12345 with app_key ` - **`ok`** `boolean` If false, the request was unsuccessful. **Examples** *Example* ```http POST /api/channels/sms HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "msisdn" : "15035556789", "sender": "12345", "opted_in": "2020-02-13T11:58:59", "timezone": "America/Los_Angeles", "locale_country": "US", "locale_language": "en", "tag_operations": { "add": { "my_fav_tag_group1": ["tag1", "tag2", "tag3"], "my_fav_tag_group2": ["tag1", "tag2", "tag3"], "my_fav_tag_group3": ["tag1", "tag2", "tag3"] } }, "attributes": { "my_fav_attribute1": "attribute1", "my_fav_attribute2": "attribute2" } } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); SmsRegistrationRequest request = SmsRegistrationRequest .newRegistrationRequest("12345", "15035556789", DateTime.parse("2020-02-13T11:58:59Z")); Response response = client.execute(request); ``` ```python from urbanairship import ( BearerTokenClient, Sms ) from datetime import datetime client = BearerTokenClient( app_key='', token='' ) sms_channel = Sms( client=client, sender="12345", msisdn="15035556789", opted_in=datetime.fromisoformat("2020-02-13T11:58:59"), locale_country="US", locale_language="en", timezone="America/Los_Angeles" ) response = sms_channel.register() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') sms_channel = UA::Sms.new(client: airship) sms_channel.msisdn = '15035556789' sms_channel.sender = '12345' sms_channel.opted_in = '2020-02-13T11:58:59' sms_channel.register ``` *Response (With 'opted_in')* ```http HTTP/1.1 201 Created Location: https://go.urbanairship.com/api/channels/7c5d7328-9bb4-4ff7-86b0-96a5f1da5868 Content-Type: application/json { "ok": true, "operation_id": "62077236-d032-11e9-af71-ab156113d166", "channel_id": "7c5d7328-9bb4-4ff7-86b0-96a5f1da5868", "attributes": {"ok": true}, "tags": {"ok": true} } ``` *Response (Without 'opted_in')* ```http HTTP/1.1 202 Accepted Content-Type: application/json Location: https://go.urbanairship.com/api/channels/79fbe330-d033-11e9-adfb-df10b89c5e04 { "ok": true, "operation_id": "62077236-d032-11e9-af71-ab156113d166", "push_id": "26350f60-d033-11e9-80e3-33def0e528d1", "channel_id": "79fbe330-d033-11e9-adfb-df10b89c5e04", "status": "pending", "attributes": {"ok": true}, "tags": {"ok": true} } ``` *Response (Project not configured with sender)* ```http HTTP/1.1 400 Bad Request Content-Type: application/json { "ok": false, "errors": "Unable to retrieve details for sender 12345 with app_key " } ``` --- ## SMS channel lookup {#getsmschannel} Lookup an SMS channel by `msisdn` and `sender`. [Jump to examples ↓](#getsmschannel-examples) ### `GET /api/channels/sms/{msisdn}/{sender}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `msisdn` | `integer` | Required | The mobile phone number you want to lookup a channel for. 15 digits maximum; may not contain leading zeroes. | | `sender` | `integer` | Required | A long or short code the app is configured to send from. | **Responses** **`200`** Returns an SMS channel object. An SMS channel object includes tag groups for `ua_channel_type`, `ua_sender_id`, and `ua_opt_in`. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`channel`** `object` <[Channel listing object]({{< ref "/developer/rest-api/ua/schemas/channels/" >}}#channellistingobject)> Describes a channel listing object. - **`ok`** `boolean` Success. **`404`** A `channel_id` does not exist for the `msisdn` and `sender`. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`error`** `string` Returned with 40x responses; explains why the request was unsuccessful. - **`error_code`** `integer` The 5-digit Airship error code, pointing to a more specific error than the HTTP status. - **`ok`** `boolean` If false, the request was unsuccessful. **Examples** *Example* ```http GET /api/channels/sms/15035556789/12345 HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Data-Attribute: channel Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "channel": { "channel_id": "84e36d69-873b-4ffe-81cd-e74c9f002057", "device_type": "sms", "installed": true, "push_address": null, "named_user_id": null, "alias": null, "tags": [], "tag_groups": { "ua_channel_type": [ "sms" ], "ua_sender_id": [ "12345" ], "ua_opt_in": [ "true" ] }, "created": "2020-04-27T22:06:21", "opt_in": true, "opt_in_date": "2022-07-07T03:23:13", "msisdn": "150355551234", "last_registration": "2020-05-14T19:51:38" } } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); ChannelRequest channelRequest = ChannelRequest.newSmsLookupRequest("15035556789","12345"); Response response = client.execute(channelRequest); ``` ```python from urbanairship import ( BasicAuthClient, Sms ) client = BasicAuthClient( key='', secret='' ) sms = Sms( client=client, sender='12345', msisdn='15035556789' ) channel_info = sms.lookup() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') sms_channel = UA::Sms.new(client: airship) sms_channel.msisdn = '15035556789' sms_channel.sender = '12345' sms_channel.lookup ``` *Example opt_out_date* ```http HTTP/1.1 200 OK Data-Attribute: channel Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "channel": { "channel_id": "84e36d69-873b-4ffe-81cd-e74c9f002057", "device_type": "sms", "installed": true, "push_address": null, "named_user_id": null, "alias": null, "tags": [], "tag_groups": { "ua_channel_type": [ "sms" ], "ua_sender_id": [ "12345" ], "ua_opt_in": [ "true" ] }, "created": "2020-04-27T22:06:21", "opt_in": false, "opt_in_date": "2022-07-07T03:23:13", "opt_out_date": "2022-07-08T03:23:13", "msisdn": "150355551234", "last_registration": "2020-05-14T19:51:38" } } ``` --- ## SMS tags {#modifysmschanneltags} Add, remove, or set tags for a single SMS channel. [Jump to examples ↓](#modifysmschanneltags-examples) ### `POST /api/channels/sms/tags` {{< important >}} A tag must be < 128 characters. A request with one or more tags longer than 128 characters will return a 400 response. We support up to 1,000 tags per channel. Adding more than 1,000 tags per channel can cause latency and service interruptions. We strongly recommend removing unused tags whenever possible, and using Custom Events when appropriate. Please [contact Support](https://support.airship.com/) if you believe your use case requires more than 1,000 tags per channel, and they will help you find an alternative. {{< /important >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** A single request body can contain an `add` and/or `remove` field or a single `set` field. One or more of the `add`, `remove`, or `set` keys must be present in the request. **Content-Type:** `application/json` - **`add`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Adds the specified tags to the channel. Tags that are already present are not modified/removed as a result of this operation. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`audience`** `object` **REQUIRED** Specifies the MSISDN and sender you want to perform tag operations against. **OBJECT PROPERTIES** - **`msisdn`** `string` The mobile phone number corresponding to the SMS channel. Must be numeric characters only, without leading zeros. 15 digits maximum. Max length: 15 - **`sender`** `string` A long or short code the app is configured to send from. For example, `12345`. - **`remove`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Removes the specified tags from the channel. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`set`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Assigns a list of tags exactly. Any previously set tags that are not in this current list are removed. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. **Responses** **`200`** Returns OK for success. If a tag request is partially valid, i.e., at least one tag group exists and is active, a 200 will be returned with a warning in the response about the tag groups that failed to update. The tag groups listed in the warning will be CSV-formatted. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/sms/tags HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "sender": "12345", "msisdn": "15035556789" }, "add": { "my_fav_tag_group1": ["tag1", "tag2", "tag3"], "my_fav_tag_group2": ["tag1", "tag2", "tag3"], "my_fav_tag_group3": ["tag1", "tag2", "tag3"] } } ``` --- ## Uninstall SMS channel {#uninstallsmschannel} **Removes phone numbers and accompanying data from Airship. Use with caution.** Uninstalling an SMS channel will prevent you from retrieving opt-in and opt-out history for the corresponding msisdn. If the uninstalled msisdn opts-in again, it will generate a new channel_id. The new channel_id cannot be reassociated with any opt-in information, tags, Named Users, Performance Analytics reports, or other information from the uninstalled SMS channel. [Jump to examples ↓](#uninstallsmschannel-examples) ### `POST /api/channels/sms/uninstall` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** **Content-Type:** `application/json` - **`msisdn`** `string` **REQUIRED** The mobile phone number you want to remove from the Airship system. Must be numeric characters only, without leading zeros. 15 digits maximum. Max length: 15 - **`sender`** `string` **REQUIRED** A long or short code the app is configured to send from. For example, `12345`. **Responses** **`202`** The SMS channel and all information associated with the msisdn is uninstalled. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` If true, the operation was successful. **`400`** The request body is not valid. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`details`** `object` **OBJECT PROPERTIES** - **`error`** `string` Specific error message that explains why the request was unsuccessful. - **`error`** `string` Returned with 40x responses; explains why the request was unsuccessful. - **`error_code`** `integer` The 5-digit Airship error code, pointing to a more specific error than the HTTP status. - **`ok`** `boolean` If false, the request was unsuccessful. **Examples** *Example* ```http POST /api/channels/sms/uninstall HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "sender": "12345", "msisdn": "15035556789" } ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); SmsRegistrationRequest request = SmsRegistrationRequest .newUninstallRequest("12345", "15035556789"); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, Sms ) client = BasicAuthClient( key='', secret='' ) sms = Sms( client=client, sender='12345', msisdn='15035556789' ) response = sms.uninstall() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') sms_channel = UA::Sms.new(client: airship) sms_channel.msisdn = '15035556789' sms_channel.sender = '12345' sms_channel.uninstall ``` --- ## Update SMS channel {#updatesmschannel} Update an existing SMS channel to reflect opt-in date, time zone and/or locale changes. The `msisdn` and `sender` in the request must match the existing channel or the request will 404. [Jump to examples ↓](#updatesmschannel-examples) ### `PUT /api/channels/sms/{channel_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `channel_id` | `string` | Required | The identifier for the SMS channel you want to update. | **Request body** **Content-Type:** `application/json` - **`locale_country`** `string` The ISO 3166 two-character country code. The value for this field becomes a tag in the `ua_locale_country` tag group. - **`locale_language`** `string` The ISO 639-1 two-character language code. The value for this field becomes a tag in the `ua_locale_language` tag group. - **`msisdn`** `string` **REQUIRED** The phone number corresponding to the `channel_id` in the request. You cannot change this value for the existing channel. Max length: 15 - **`opted_in`** `string` The [date-time](/docs/developer/rest-api/ua/introduction/#date-time-format) that represents when explicit permission was received from the user to receive messages. Format: `date-time` - **`sender`** `string` **REQUIRED** The sender corresponding to the `channel_id` in the request. You cannot change this value for an existing channel. - **`timezone`** `string` The IANA identifier for a time zone, e.g., `America/Los_Angeles`. The value in this field becomes a tag in the `timezone` tag group. **Responses** **`200`** The SMS channel was updated successfully. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` True if the request was successful. - **`operation_id`** `string` A unique identifier for an operation; you can use this identifier to find the operation for troubleshooting purposes. Format: `uuid` **`400`** The request to update the channel failed. This error occurs when the MSISDN does not fall into the geographical region supported by the sender or the request is incorrect, e.g., missing or mismatching `msisdn` or `sender`, the `msisdn` is not a valid E.164 standard MSISDN, or invalid timezone/locale values are supplied. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`errors`** `string` Returned with 40x responses; explains reason for the unsuccessful request. Example: `Unable to retrieve details for sender 12345 with app_key ` - **`ok`** `boolean` If false, the request was unsuccessful. **`404`** Occurs when the `msisdn` and/or `sender` don't match any existing `channel_id`. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`errors`** `string` A plain-text explanation of the error. - **`ok`** `boolean` If false, your request was unsuccessful. **Examples** *Example* ```http PUT /api/channels/sms/{channel_id} HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "msisdn": "15035556789", "sender": "12345", "opted_in": "2020-02-13T11:58:59", "timezone": "America/Los_Angeles", "locale_country": "US", "locale_language": "en" } ``` ```http HTTP/1.1 200 OK Content-Type: application/json { "ok": true, } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); UpdateSmsChannel updateSmsChannel = UpdateSmsChannel.newBuilder() .setMsisdn("13609048615") .setSender("17372004196") .setOptedIn(DateTime.parse("2021-10-11T02:03:03")) .setLocaleCountry("US") .setLocaleLanguage("en") .setTimeZone("America/Los_Angeles") .build(); UpdateSmsChannelRequest updateSmsChannelRequest = UpdateSmsChannelRequest.newRequest("308303cf-9c10-4d71-9bc2-d9f3a671ed0c", updateSmsChannel); Response response = client.execute(updateSmsChannelRequest); ``` ```python from urbanairship import ( BearerTokenClient, Sms ) from datetime import datetime client = BearerTokenClient( app_key='', token='' ) sms_channel = Sms( client=client, sender="12345", msisdn="15035556789", opted_in=datetime.fromisoformat("2021-02-13T11:58:59"), locale_country="US", locale_language="en", timezone="America/Los_Angeles" ) # Update properties sms_channel.locale_country = "FR" sms_channel.opted_in = datetime.fromisoformat("2020-02-13T11:58:59") response = sms_channel.update() ``` --- # Static Lists > With the Static List API endpoint, you can target and manage lists of devices that are defined in systems outside of Airship. Any list or grouping of devices for which the canonical source of data about the members is elsewhere is a good candidate for Static Lists, e.g., members of a customer loyalty program. In the dashboard, they are referred to as [Uploaded Lists](/guides/audience/segmentation/audience-lists/uploaded/). Airship automatically deletes a Static list and all its versions after 90 days of inactivity. Timestamps used to calculate the 90-day period are the creation date, when updating list contents or metadata, and when sending a message (pushing) to the list. The creation date is the initial day one of the 90-day period. Each instance of updating or sending to the list resets the timestamp to day one. After automatic deletion or deleting from the Airship dashboard, the list is removed from the upload history, is no longer visible in the Airship dashboard or through API calls, and is no longer available for audience segmentation. ## Create list {#createstaticlist} Create a static list. The body of the request will contain several of the list object parameters, but the actual list content will be provided by a second call to the [upload](/docs/developer/rest-api/ua/operations/static-lists/#updatestaticlist) endpoint. You can upload up to 100 lists per project. [Jump to examples ↓](#createstaticlist-examples) ### `POST /api/lists` {{< note >}} `Content-Encoding: gzip` is supported and recommended on this endpoint to reduce network traffic. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Request body** **Content-Type:** `application/json` - **`description`** `string` An optional description for the list. Min length: 1, Max length: 1000 - **`extra`** `object` An optional JSON map of up to 100 key-value (string-to-string) pairs associated with the list. Keys in this object have a 64-character maximum; values can be up to 1,024 characters. - **`name`** `string` **REQUIRED** The name of the list, consists of up to 64 URL-safe characters. The name is how the list is identified, so it should be unique and memorable. Note: Since the `name` portion of the URL may represent any Unicode string, it must be encoded properly as a URI path component. The `encodeURIComponent` function in JavaScript can be used. Min length: 1, Max length: 64 **Responses** **`201`** The list was created successfully. Response headers: | Name | Type | Description | |------|------|-------------| | `Location` | `string` | The URI of the list, used for later updates. | Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`409`** The request conflicts with another request. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/lists HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "name" : "platinum_members", "description" : "loyalty program platinum members", "extra" : { "key" : "value", "another" : "etc." } } ``` ```http HTTP/1.1 201 Created Location: https://go.urbanairship.com/api/lists/platinum_members Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); StaticListRequest request = StaticListRequest.newRequest("platinum_members") .setDescription("loyalty program platinum members") .addExtra("key", "value"); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, StaticList ) client = BasicAuthClient( key='', secret='' ) # Create a new static list static_list = StaticList( client=client, name='platinum_members' ) static_list.description = 'loyalty program platinum members' static_list.extra = {'key': 'value'} response = static_list.create() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') static_list = UA::StaticList.new(client: airship) static_list.name = 'platinum_members' static_list.create(description: 'loyalty program platinum members') ``` --- ## Delete a list {#deletestaticlist} Delete a static list. [Jump to examples ↓](#deletestaticlist-examples) ### `DELETE /api/lists/{list_name}` {{< warning >}} If you are attempting to update a current list by deleting it and then recreating it with new data, stop and go to the [upload endpoint](/docs/developer/rest-api/ua/operations/static-lists/#updatestaticlist). There is no need to delete a list before uploading a new CSV file. Moreover, once you delete a list, you will be unable to create a list with the same name as the deleted list. {{< /warning >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `list_name` | `string` | Required | The name of the list. | **Responses** **`204`** An API request was successful, but there is no response body to return. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** You cannot delete or modify lists with a `ua_` prefixed `name`. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http DELETE /api/lists/platinum_members HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 204 No Content ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); StaticListDeleteRequest request = StaticListDeleteRequest.newRequest("platinum_members"); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, StaticList ) client = BasicAuthClient( key='', secret='' ) # Delete a static list static_list = StaticList( client=client, name='platinum_members' ) response = static_list.delete() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') static_list = UA::StaticList.new(client: airship) static_list.name = 'platinum_members' static_list.delete ``` --- ## Download a list of channels {#getstaticlist} Allows you to download the contents of a static list (as opposed to a `GET` `/api/lists/{list_name}`, which will return metadata about the list). The CSV output from this endpoint will only include entries originally uploaded as `ios_channel`, `android_channel`, or `amazon_channel`. [Jump to examples ↓](#getstaticlist-examples) ### `GET /api/lists/{list_name}/csv` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `list_name` | `string` | Required | The `name` of the list you want to retrieve or update. | **Responses** **`200`** Returns a CSV list of channels. Response body: **Content-Type:** `text/csv` Type: `string` **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/lists/foobar/csv HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+csv; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: text/csv ios_channel,6d56ab7e-2c78-4ba9-ab11-d9b664ca2b32 ios_channel,d5ebe607-a3e6-4601-b97e-83ec604223fe ios_channel,fa599af7-43e4-4862-a570-1470bf6f53ff android_channel,0e91d0f2-c65d-4b40-b968-b9f8e8b0c987 android_channel,c346a3ce-5754-4d02-8ee5-500ce470a0b7 android_channel,e9a01369-5f74-4167-b660-df84014a2e57 amazon_channel,0356d138-d1d9-4572-b321-e1b67f4cd658 amazon_channel,24dc9a76-45fe-4b17-8ed7-841f96b658ad amazon_channel,4d6b59f8-6d8c-4151-8b13-cd58d6ac8c6e ``` ```python from urbanairship import ( BasicAuthClient, StaticList ) client = BasicAuthClient( key='', secret='' ) # Download a static list response = StaticList.download( client=client, list_name='platinum_members' ) ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); StaticListDownloadRequest request = StaticListDownloadRequest.newRequest("foobar"); Response response = client.execute(request); ``` --- ## Get single list metadata {#getstaticlistmetadata} Retrieve information about one static list, specified in the URL. When looking up lists, the returned information may actually be a combination of values from both the last uploaded list and the last successfully processed list. If you create a list successfully, and then you update it and the processing step fails, then the list `status` will read `failed`, but the `channel_count` and `last_modified` fields will contain information on the last successfully processed list. [Jump to examples ↓](#getstaticlistmetadata-examples) ### `GET /api/lists/{list_name}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `list_name` | `string` | Required | The name of the list. | **Responses** **`200`** List metadata retrieved successfully. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`description`** `string` An optional description for the list. Min length: 1, Max length: 1000 - **`extra`** `object` An optional JSON map of up to 100 key-value (string-to-string) pairs associated with the list. Keys in this object have a 64-character maximum; values can be up to 1,024 characters. - **`name`** `string` The name of the list, consists of up to 64 URL-safe characters. The name is how the list is identified, so it should be unique and memorable. Min length: 1, Max length: 64 - **`ok`** `boolean` Success. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/lists/platinum_members/ HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Data-Attribute: static_list Link: ; rel=next Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "name" : "platinum_members", "description" : "loyalty program platinum members", "extra" : { "key" : "value" }, "created" : "2020-04-08T20:41:06", "last_updated" : "2020-05-01T18:00:27", "channel_count" : 1000, "status" : "ready" } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); StaticListLookupRequest request = StaticListLookupRequest.newRequest("platinum_members"); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, StaticList ) client = BasicAuthClient( key='', secret='' ) # Look up a static list static_list = StaticList( client=client, name='platinum_members' ) response = static_list.lookup() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') static_list = UA::StaticList.new(client: airship) static_list.name = 'platinum_members' static_list.lookup ``` --- ## Retrieve lists {#getstaticlistsmetadata} Retrieve information about all static lists. This call returns a list of metadata that will not contain the actual lists of users. [Jump to examples ↓](#getstaticlistsmetadata-examples) ### `GET /api/lists` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Responses** **`200`** Lists metadata retrieved successfully. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`lists`** `array` <[List response object]({{< ref "/developer/rest-api/ua/schemas/others/" >}}#listobject)> An array of list objects. - **`ok`** `boolean` Success. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/lists HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Data-Attribute: lists Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "lists" : [ { "name" : "platinum_members", "description" : "loyalty program platinum members", "extra" : { "key" : "value" }, "created" : "2020-04-08T20:41:06", "last_modified" : "2020-05-01T18:00:27", "channel_count": 3145, "status": "ready" }, { "name": "gold_members", "description": "loyalty program gold member", "extra": { "key": "value" }, "created": "2020-04-08T20:41:06", "last_updated": "2020-05-01T18:00:27", "channel_count": 678, "status": "ready" } ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); StaticListListingRequest request = StaticListListingRequest.newRequest(); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, StaticLists ) client = BasicAuthClient( key='', secret='' ) # List all static lists static_lists = StaticLists(client) for static_list in static_lists: print( static_list.name, static_list.description, static_list.extra, static_list.created, static_list.last_updated, static_list.channel_count, static_list.status ) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') static_lists = UA::StaticLists.new(client: airship) static_lists.each do |static_list| puts(static_list) end ``` --- ## Update list contents {#updatestaticlist} Replace the contents of an existing static list via CSV file upload. Uploads must be newline-delimited identifiers (text/CSV) with commas as the delimiter. The CSV format is two columns: `identifier_type` and `identifier`. The `identifier` is the associated identifier you wish to send to. The `identifier_type` must be one of: * `named_user` * `ios_channel` * `android_channel` * `amazon_channel` * `sms_channel` * `email_channel` * `open_channel` * `web_channel` The first entry in the uploaded CSV may be a header row, which will be ignored. If present, the header row must contain exactly two entries, and the first column must not be an `identifier_type` as specified above. [Jump to examples ↓](#updatestaticlist-examples) ### `PUT /api/lists/{list_name}/csv` {{< note >}} The maximum number of `identifier_type,identifier` pairs that may be uploaded to a list is 10 million. `Content-Encoding: gzip` is supported and recommended on this endpoint to reduce network traffic. {{< /note >}} {{< warning >}} If an attempt to upload a list times out due to a poor connection, you must re-upload the list from scratch. Because we want to ensure that the entirety of a given list is successfully uploaded, we do not support partial list uploads. {{< /warning >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `list_name` | `string` | Required | The `name` of the list you want to retrieve or update. | **Request body** **Content-Type:** `text/csv` Type: `string` **Responses** **`202`** The request has been accepted for processing. Response body: **Content-Type:** `application/json` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** Bad Request. Parsing or validating the request failed. | Error code | Description | |---|---| | 40002 | CSV contains too many identifiers | | 40003 | CSV contains an entry with a column count other than 2 | | 40004 | CSV contains an invalid `identifier_type` | | 40005 | CSV contains a channel `identifier` that is not a valid UUID | Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http PUT /api/lists/platinum_members/csv HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: text/csv named_user,customer-42 named_user,room-27 ios_channel,5i4c91s5-9tg2-k5zc-m592150z5634 web_channel,d132f5b7-abcf-4920-aeb3-9132ddac3d5a android_channel,52b2b587-0152-4134-a8a0-38ae6933c88a email_channel,ab1a81e3-5af3-4c04-a7ae-d676960e6684 open_channel,6bcf3e63-a38a-44d8-8b0d-2fb5941e74ab sms_channel,ab1a81e3-aaf3-ac04-a7ae-a676960e6684 ``` ```http HTTP/1.1 202 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); File dataDirectory = new File("src/data"); String filePath = dataDirectory.getAbsolutePath() + "/platinum.csv"; StaticListUploadRequest request = StaticListUploadRequest.newRequest("platinum_members", filePath); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, StaticList ) client = BasicAuthClient( key='', secret='' ) # Upload a CSV file to a static list static_list = StaticList( client=client, name='platinum_members' ) with open('list.csv', 'r') as csv_file: response = static_list.upload(csv_file) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') static_list = UA::StaticList.new(client: airship) static_list.name = 'platinum_members' File.open('csv_file', 'rb') do |csv| static_list.upload(csv_file: csv, gzip: false) end ``` *Example request with header row* ```http PUT /api/lists/foobar/csv HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: text/csv Identifier Type,Identifier alias,some-user-12345 alias,some-user-12346 ios_channel,5b1a81e3-5af3-4c04-a7ae-d676960e6684 named_user,SODFHsodfuJ9433 named_user,"contains,comma" named_user,"contains""double-quote" ``` --- ## Update list metadata {#updatestaticlistmetadata} Update the metadata (`description`, `extras`, etc.) of a static list. [Jump to examples ↓](#updatestaticlistmetadata-examples) ### `PUT /api/lists/{list_name}` {{< note >}} To update the list contents, use the [list upload](/docs/developer/rest-api/ua/operations/static-lists/#updatestaticlist) endpoint. The update endpoint is used to update a list's metadata rather than the actual list of device identifiers. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `list_name` | `string` | Required | The name of the list. | **Request body** The body of the request will contain a list metadata object, though you can omit the `name` attribute. If present, it must match the name provided in the URL. You cannot change the name of a list; it is the primary identifier for the list. **Content-Type:** `application/json` - **`description`** `string` An optional description for the list. Min length: 1, Max length: 1000 - **`extra`** `object` An optional JSON map of up to 100 key-value (string-to-string) pairs associated with the list. Keys in this object have a 64-character maximum; values can be up to 1,024 characters. - **`name`** `string` **REQUIRED** The name of the list, consists of up to 64 URL-safe characters. The name is how the list is identified, so it should be unique and memorable. Note: Since the `name` portion of the URL may represent any Unicode string, it must be encoded properly as a URI path component. The `encodeURIComponent` function in JavaScript can be used. Min length: 1, Max length: 64 **Responses** **`200`** The list metadata was updated successfully. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** Bad Request. Parsing or validating the request failed. error_code 40001: Attempted list rename. List renaming is not allowed. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Forbidden. Authentication was correct, but the user does not have permission to access the requested API, e.g., the API may not be used to create or modify lists with a `ua_` prefixed name. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http PUT /api/lists/platinum_members HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "name" : "platinum_members", "description" : "loyalty program platinum members", "extra" : { "key" : "value" } } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); StaticListRequest request = StaticListRequest.newUpdateRequest("platinum_members") .setDescription("loyalty program platinum members") .addExtra("key", "value"); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, StaticList ) client = BasicAuthClient( key='', secret='' ) # Update an existing static list static_list = StaticList( client=client, name='platinum_members' ) static_list.description = 'loyalty program platinum members' static_list.extra = {'key': 'value'} response = static_list.update() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') static_list = UA::StaticList.new(client: airship) static_list.name = 'platinum_members' static_list.update(description: 'loyalty program platinum members') ``` --- # Subscription Lists > Create, manage, and add or remove channels from subscription lists. ## Named User subscription lists listing {#getnamedusersubscriptionlists} Provides the subscription lists that are associated with a given Named User. [Jump to examples ↓](#getnamedusersubscriptionlists-examples) ### `GET /api/subscription_lists/named_users/{named_user_id}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): nu **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `named_user_id` | `string` | Required | The Named User being looked up. | **Responses** **`200`** Returns OK for success, with the Named User subscription list IDs. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` Success. - **`subscription_lists`** `array` <[Contact Subscription List object]({{< ref "/developer/rest-api/ua/schemas/subscription-lists/" >}}#contactsubscriptionlistobject)> **`304`** An If-Modified-Since request header exists and the result is unchanged. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/subscription_lists/named_users/4cbd1c1c-42e1-4606-bc93-9b707bcedcbc HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "subscription_lists": [ { "list_ids": ["example_listId-2", "example_listId-4"], "scope": "app" }, { "list_ids": ["example_listId-2"], "scope": "web" } ], } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); NamedUserSubscriptionListsListingRequest namedUserSubscriptionListsListingRequest = NamedUserSubscriptionListsListingRequest.newRequest("4cbd1c1c-42e1-4606-bc93-9b707bcedcbc"); Response response = client.execute(namedUserSubscriptionListsListingRequest); ``` ```python from urbanairship import ( BasicAuthClient, SubscriptionList ) client = BasicAuthClient( key='', secret='' ) # Get subscription lists for a named user named_user_lists = SubscriptionList(client).list_by_named_user('4cbd1c1c-42e1-4606-bc93-9b707bcedcbc') ``` --- ## Subscription lists listing {#getsubscriptionlists} Provides a list of subscription lists IDs that are associated with this app key. [Jump to examples ↓](#getsubscriptionlists-examples) ### `GET /api/subscription_lists` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Responses** **`200`** Returns OK for success, with the list of subscription lists for the app. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` Success. - **`subscription_lists`** `array` <[Subscription List result object]({{< ref "/developer/rest-api/ua/schemas/subscription-lists/" >}}#subscriptionlistresultobject)> An array of subscription list result objects. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/subscription_lists HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "subscription_lists": [ { "list_id": "example_listId-1", "name": "A nice readable name 1", "scopes": ["email"], "messaging_type": "transactional", "default_opted_in": false }, { "list_id": "example_listId-2", "name": "A nice readable name 2", "description": "A very nice description for you.", "scopes": ["app", "web"], "default_opted_in": true } ] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); SubscriptionListListingRequest subscriptionListListingRequest = SubscriptionListListingRequest.newRequest(); Response response = client.execute(subscriptionListListingRequest); ``` ```python from urbanairship import ( BasicAuthClient, SubscriptionList ) client = BasicAuthClient( key='', secret='' ) # List all subscription lists subscription_lists = SubscriptionList(client).list() ``` --- # Tag Lists > Manage tag lists for organizing and applying tags in bulk. {{< note >}} You cannot update channel information or opt-in status from these endpoints. To update channels, use the appropriate channel registration endpoints. {{< /note >}} ## Create a tag list {#createtaglist} Add tags to your contacts by creating a list and uploading CSV file with user identifiers. The body of the request contains the name, description, and optional metadata for the list. After you define a list, you populate it with a call to the [Upload Tag List](/docs/developer/rest-api/ua/operations/tag-lists/#uploadtaglist) endpoint. [Jump to examples ↓](#createtaglist-examples) ### `POST /api/tag-lists` {{< important >}} You must prefix tag list names with `"ua_tags_"`. {{< /important >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Request body** **Content-Type:** `application/json` [Tag List metadata object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taglistmetadataobject) **Responses** **`201`** The list was created successfully. Response headers: | Name | Type | Description | |------|------|-------------| | `Location` | `string` | The URI of the list, used for later updates. | Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`409`** The request conflicts with another request. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/tag-lists HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "name":"ua_tags_foobar", "description":"Description of the file being uploaded", "extra":{ "key":"value", "another":"etc..." }, "add":{ "tag-group-name":[ "tag-value" ], "tag-group-name2":[ "tag-value2a", "tag-value2b" ] }, "remove":{ "tag-group-name3":[ "tag-value" ] }, "set":{ "tag-group-name4":[ "tag-value" ] } } ``` ```http HTTP/1.1 201 Created Content-Type: application/json Location: https://go.urbanairship.com/api/tag-lists/ua_tags_foobar { "ok" : true } ``` ```python from urbanairship import ( BasicAuthClient, TagList ) client = BasicAuthClient( key='', secret='' ) tag_list = TagList( client=client, list_name="ua_tags_my_new_list", description="First of many tags lists!", extra={ "filename": "tags.csv", "source": "CRM" }, add_tags={ "tag-group-name": ["tag-value"], "tag-group-name2": ["tag-value2a", "tag-value2b"] }, remove_tags={ "tag-group-name3": ["tag-value"] }, set_tags={ "tag-group-name4": ["tag-value"] } ) tag_list.create() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: 'app_key', secret: 'master_secret') tags = {'tag_group_name': ['tag1', 'tag2']} tag_list = UA::TagList.new(client: airship) tag_list.name = 'ua_tags_list_name' tag_list.create(description: 'description', extra: {'key': 'value'}, add: tags) ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); TagListRequest tagListRequest = TagListRequest.newRequest() .setName("ua_tags_my_new_list"); .setDescription("First of many tags lists!") .addTags("tag_group1", ImmutableSet.of("tag1","tag2")) .removeTags("tag_group2", ImmutableSet.of("tag3","tag4")) .setTags("tag_group3", ImmutableSet.of("tag4","tag5")) .addExtra("test","value") Response response = client.execute(tagListRequest); ``` --- ## Delete tag list {#deletetaglist} Delete a list. Deleting a list will not affect any previous uploads but will prevent new uploads to the deleted list. For example, this does not remove the tags associated with the previously-uploaded file from the channels in that file. [Jump to examples ↓](#deletetaglist-examples) ### `DELETE /api/tag-lists/{list_name}` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `list_name` | `string` | Required | The name of the list. | **Responses** **`204`** The delete operation was successful. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http DELETE /api/tag-lists/ua_tags_foobar HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+csv; version=3 ``` ```http HTTP/1.1 204 No Content ``` --- ## Download list errors {#gettaglisterrors} During processing, after a list is uploaded, errors can occur. Depending on the type of list processing, an error file may be created, showing a user exactly what went wrong. [Jump to examples ↓](#gettaglisterrors-examples) ### `GET /api/tag-lists/{list_name}/errors` **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `list_name` | `string` | Required | The name of the list. | **Responses** **`200`** Returns OK for success. The response will contain the errors found during list processing. Response body: **Content-Type:** `text/csv` Type: `string` **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/tag-lists/ua_tags_foobar/errors HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+csv; version=3 ``` ```http HTTP/1.1 200 OK Content-Type: text/csv 8b4de669-16f1-4e71-9a1f-0c62a8235a65,ERROR,"Unknown channel" abcd,ERROR,"Invalid msisdn" ``` ```python from urbanairship import ( BasicAuthClient, TagList ) client = BasicAuthClient( key='', secret='' ) tag_list = TagList( airship=client, list_name="ua_tags_foobar", description="example list", ) errors = tag_list.get_errors() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: 'app_key', secret: 'master_secret') tag_list = UA::TagList.new(client: airship) error_csv = tag_list.errors ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); TagListErrorsRequest request = TagListErrorsRequest.newRequest("ua_tags_foobar"); Response response = client.execute(request); ``` --- ## Retrieve lists {#gettaglistsmetadata} Retrieve information about all tag lists. This call returns a list of metadata that will not contain the actual lists of users. [Jump to examples ↓](#gettaglistsmetadata-examples) ### `GET /api/tag-lists` {{< note >}} The tag list content will return the data provided in the [tag list creation](/docs/developer/rest-api/ua/operations/tag-lists/#createtaglist) operation. Although `add`, `remove`, and `set` are optional, one or more must be present. {{< /note >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Responses** **`200`** Lists metadata retrieved successfully. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`lists`** `array` <[Tag List response object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taglistresponseobject)> An array of list objects. - **`ok`** `boolean` Success. **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http GET /api/tag-lists HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 ``` ```http HTTP/1.1 200 OK Data-Tag: lists Content-Type: application/vnd.urbanairship+json; version=3 { "ok" : true, "lists" : [ { "name" : "ua_tags_foo", "description" : "", "extra" : { "key": "value" }, "add":{ "tag-group-name": [ "tag-value" ], "tag-group-name2": [ "tag-value2a", "tag-value2b" ] }, "remove": { "tag-group-name3": [ "tag-value" ] }, "set": { "tag-group-name4": [ "tag-value" ] }, "created" : "2013-08-08T20:41:06", "last_updated" : "2014-05-01T18:00:27", "channel_count" : 0, "mutation_success_count": 1000, "mutation_error_count": 10, "error_path": "https://go.urbanairship.com/api/tag-lists/users_a/errors", "status" : "ready" }, { "..." : "..." } ] } ``` ```python from urbanairship import ( BasicAuthClient, TagList ) client = BasicAuthClient( key='', secret='' ) # List all tag lists response = TagList.list(airship=client) tag_lists = response.json() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: 'app_key', secret: 'master_secret') tag_list = UA::TagList.new(client: airship) list_response = tag_list.list ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); TagListListingRequest tagListListingRequest = TagListListingRequest.newRequest(); Response response = client.execute(tagListListingRequest); ``` --- ## Upload tag list {#uploadtaglist} Upload a CSV that will set tag values on the specified channels or Named Users. The first entry in the uploaded CSV must be a header row. The first field must be one of the following identifier types: `channel_id`, `msisdn`, `named_user`, `email_address`. Only one identifier type is allowed per file. You must include both `msisdn` and `sms_sender` columns when targeting SMS or MMS channel types. See example to the right. Uploads must be newline-delimited identifiers (text/CSV) as described in RFC 4180, with commas as the delimiter, optionally double-quoted values, UTF-8 encoded, and with CRLF or LF line separators. | Target type | Required column headers | |------------------|------------------------------------------------------------------------------------------| | Web | `channel_id` | | Open Channel | `channel_id` | | iOS | `channel_id` | | Android | `channel_id` | | Named User | `named_user` | | Email | `email_address` | | SMS |
  • `msisdn` (numeric and no leading 0)
  • `sms_sender` (numeric)
| | MMS |
  • `msisdn` (numeric and no leading 0)
  • `sms_sender` (numeric)
| Optional Fields: Opt-in dates can optionally be set for new channels when the identifier is an `email_address` or `msisdn`. | Target type | Optional column headers | |-----------------|------------------------------------------------------------------------------------------| | SMS | `ua_opted_in` (UTC Timestamp) | | MMS | `ua_opted_in` (UTC Timestamp) | | Email |
  • `ua_transactional_opted_in` (UTC Timestamp)
  • `ua_commercial_opted_in` (UTC Timestamp)
| [Jump to examples ↓](#uploadtaglist-examples) ### `PUT /api/tag-lists/{list_name}/csv` {{< note >}} The maximum number of rows that may be uploaded to a list is 10 million. `Content-Encoding: gzip` is supported and recommended on this endpoint to reduce network traffic. {{< /note >}} {{< warning >}} If your upload times out due to a poor connection, you must re-upload the list from scratch. Because we want to ensure that the entirety of a given list is successfully uploaded, we do not support partial list uploads. {{< /warning >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): lst **Path parameters:** | Name | Type | Required | Description | |------|------|----------|-------------| | `list_name` | `string` | Required | The `name` of the list you want to retrieve or update. | **Request body** **Content-Type:** `text/csv` Type: `string` **Responses** **`202`** The request has been accepted for processing. Response body: **Content-Type:** `application/json` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** Bad Request. Parsing or validating the request failed. | Error code | Description | |---|---| | 40002 | CSV contains too many identifiers | | 40003 | CSV header contains too many columns | | 40013 | CSV header’s first field must be an identifier | | 40018 | CSV header does not contain required column for identifier type | Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`404`** The requested resource doesn't exist. Response body: **Content-Type:** `application/vnd.urbanairship+json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http PUT /api/tag-lists/ua_tags_foobar/csv HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: text/csv channel_id c543f3a3-bc1d-4830-8dee-7532c6a23b9a 6ba360a0-1f73-4ee7-861e-95f6c1ed6410 15410d17-687c-46fa-bbd9-f255741a1523 c2c64ef7-8f5c-470e-915f-f5e3da04e1df ``` ```http HTTP/1.1 202 Accepted Content-Type: application/json { "ok" : true } ``` ```python from urbanairship import ( BasicAuthClient, TagList ) client = BasicAuthClient( key='', secret='' ) tag_list = TagList( client=client, list_name="ua_tags_cool_list", description="example list" ) tag_list.upload(file_path="path/to/file.csv") ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: 'app_key', secret: 'master_secret') tag_list = UA::TagList.new(client: airship) tag_list.name = 'ua_tags_list_name' tag_list.upload(csv_file: 'file_content', gzip: true) ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); TagListUploadRequest tagListUploadRequest = TagListUploadRequest.newRequest("ua_tags_cool_list", "path/to/file.csv"); Response response = client.execute(tagListUploadRequest); ``` *Tag list CSV upload for SMS* ```http PUT /api/tag-lists/ua_tags_foobar/csv HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: text/csv msisdn,sms_sender,firstName 5035556789,18588675309,Jane 4155551212,18588675309,Rory ``` ```http HTTP/1.1 202 Accepted Content-Type: application/json { "ok" : true } ``` ```python from urbanairship import ( BasicAuthClient, TagList ) client = BasicAuthClient( key='', secret='' ) tag_list = TagList( client=client, list_name="ua_tags_foobar", description="example list" ) tag_list.upload(file_path="path/to/sms_file.csv") ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: 'app_key', secret: 'master_secret') tag_list = UA::TagList.new(client: airship) tag_list.name = 'ua_tags_list_name' tag_list.upload(csv_file: 'sms_file_content', gzip: true) ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); TagListUploadRequest tagListUploadRequest = TagListUploadRequest.newRequest("ua_tags_cool_list", "path/to/sms_file.csv.csv"); Response response = client.execute(tagListUploadRequest); ``` --- # Tags > Operations to assign or unassign tags for Channels and Named Users. Tags belong to Tag Groups and can help you organize channels using identifiers relevant to your operations. See the linked for information about, and strategies for using, tag groups. {{< note >}} If you previously used the `/api/tags` endpoint to set tags, it is strongly recommended that you transition to the endpoints and methods specified in this document. {{< /note >}} ## Channel tags {#modifychanneltags} Add, remove, or set tags on a channel. [Jump to examples ↓](#modifychanneltags-examples) ### `POST /api/channels/tags` {{< important >}} A tag must be < 128 characters. A request with one or more tags longer than 128 characters will return a 400 response. We support up to 1,000 tags per channel. Adding more than 1,000 tags per channel can cause latency and service interruptions. We strongly recommend removing unused tags whenever possible, and using Custom Events when appropriate. Please [contact Support](https://support.airship.com/) if you believe your use case requires more than 1,000 tags per channel, and they will help you find an alternative. {{< /important >}} **Security:** - [basicAppAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAppAuth) - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** **Content-Type:** `application/json` - **`add`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Adds the specified tags to the channel. Tags that are already present are not modified/removed as a result of this operation. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`audience`** `object` **REQUIRED** Specifies one or more channels that you want to apply tag operations to. **OBJECT PROPERTIES** - **`amazon_channel`** `array[string]` The unique channel identifier for a Fire OS device. Min items: 1, Max items: 1000 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` - **`android_channel`** `array[string]` The unique channel identifier for an Android device. Min items: 1, Max items: 1000 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` - **`channel`** `array[string]` The unique channel identifier for `email`, `sms`, `open`, or `web` device types. Min items: 1, Max items: 1000 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` - **`ios_channel`** `array[string]` The unique channel identifier for an iOS device. Min items: 1, Max items: 1000 Example: `00256e0b-b02f-4f12-a77f-4c3d57078330,f59970d3-3d42-4584-907e-f5c57f5d46a1` - **`remove`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Removes the specified tags from the channel. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`set`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Assigns a list of tags exactly. Any previously set tags that are not in this current list will be removed. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. **Responses** **`200`** Returns OK for success. If a tag request is partially valid, i.e., at least one tag group exists and is active, a 200 is returned with a warning in the response about the tag groups that failed to update. The tag groups listed in the warning will be CSV-formatted. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` - **`ok`** `boolean` If true, your request was processed normally. - **`warnings`** `array[string]` Returned when some tag groups could not be updated. Contains a string indicating each tag group that could not be updated and the reason the update failed. **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/tags HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "ios_channel": "b8f9b663-0a3b-cf45-587a-be880946e881", "android_channel": "13863b3c-f860-4bbf-a9f1-4d785379b8a2" }, "add": { "my_fav_tag_group1": ["tag1", "tag2", "tag3"], "my_fav_tag_group2": ["tag1", "tag2", "tag3"], "my_fav_tag_group3": ["tag1", "tag2", "tag3"] } } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true, "warnings": ["The following tag groups do not exist: my_fav_tag_group2", "The following tag groups are deactivated: my_fav_tag_group3"] } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); ChannelTagRequest request = ChannelTagRequest.newRequest() .addIOSChannel("b8f9b663-0a3b-cf45-587a-be880946e881") .addAndroidChannel("13863b3c-f860-4bbf-a9f1-4d785379b8a2") .addTags("my_fav_tag_group1", ImmutableSet.of("tag1", "tag2", "tag3")) .addTags("my_fav_tag_group2", ImmutableSet.of("tag1", "tag2", "tag3")) .addTags("my_fav_tag_group3", ImmutableSet.of("tag1", "tag2", "tag3")); Response response = client.execute(request); ``` ```python import urbanairship as ua client = ua.BasicAuthClient('', '') channel_tags = ua.devices.ChannelTags(client) ios_audience = ['b8f9b663-0a3b-cf45-587a-be880946e881'] android_audience = ['13863b3c-f860-4bbf-a9f1-4d785379b8a2'] channel_tags.set_audience(ios_audience, android_audience ) channel_tags.add('my_fav_tag_group1', ['tag1', 'tag2', 'tag3']) channel_tags.remove('my_fav_tag_group2', 'tag4') channel_tags.send() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') channel_tags = UA::ChannelTags.new(client: airship) ios_audience = 'b8f9b663-0a3b-cf45-587a-be880946e881' android_audience = '13863b3c-f860-4bbf-a9f1-4d785379b8a2' channel_tags.set_audience( ios: ios_audience, android: android_audience ) channel_tags.add(group_name: 'my_fav_tag_group1', tags: ['tag1', 'tag2', 'tag3']) channel_tags.remove(group_name: 'my_fav_tag_group2', tags: 'tag4') channel_tags.send_request ``` --- ## Contacts tags {#modifycontacttags} Add, remove, or set tags on a Contact. A single request body may contain add and/or remove objects or a single set field. At least one of the add, remove, or set objects must be present in a request. ### `POST /api/contacts/tags/` {{< important >}} A tag must be < 128 characters. A request with one or more tags longer than 128 characters will return a 400 response. We support up to 1,000 tags per Contact. Adding more than 1,000 tags per Contact can cause latency and service interruptions. We strongly recommend removing unused tags whenever possible, and using Custom Events when appropriate. Please [contact Support](https://support.airship.com/) if you believe your use case requires more than 1,000 tags per Contact, and they will help you find an alternative. {{< /important >}} **Security:** - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): cnt **Request body** **Content-Type:** `application/json` - **`add`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Add the list of tags to the Contacts, but do not remove any. If the tags are already present, they are not modified. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`audience`** `object` **REQUIRED** The Contacts you want to associate/disassociate tags with. **OBJECT PROPERTIES** - **`contact_id`** `array[string]` Min items: 1, Max items: 1000 - **`remove`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Remove the list of tags from the Contacts, but do not remove any others. If the tags are not currently present, nothing happens. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`set`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Set these tags for the audience. Any tags previously associated with the audience tags that are not in this current list are removed. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. **Responses** **`200`** If a tag request is partially valid, i.e., at least one tag group exists and is active, a 200 will be returned with a warning in the response about the tag groups that failed to update. The tag groups listed in the warning will be CSV-formatted. Response body: **Content-Type:** `application/json` - **`ok`** `boolean` **REQUIRED** Set to `true` when status code is `200`. - **`tag_warnings`** `string` Warnings encountered when processing tags for this Contact. **`400`** Parsing or validating the request failed. You will see this error if the same tag is present in both the add and remove fields. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) --- ## Email tags {#modifyemailchanneltags} Add, remove, or set tags for a single email channel. [Jump to examples ↓](#modifyemailchanneltags-examples) ### `POST /api/channels/email/tags` {{< important >}} A tag must be < 128 characters. A request with one or more tags longer than 128 characters will return a 400 response. We support up to 1,000 tags per channel. Adding more than 1,000 tags per channel can cause latency and service interruptions. We strongly recommend removing unused tags whenever possible, and using Custom Events when appropriate. Please [contact Support](https://support.airship.com/) if you believe your use case requires more than 1,000 tags per channel, and they will help you find an alternative. {{< /important >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** A single request body can contain an `add` and/or `remove` field or a single `set` field. One or more of the `add`, `remove`, or `set` keys must be present in the request. **Content-Type:** `application/json` - **`add`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Adds the specified tags to the channel. Tags that are already present are not modified/removed as a result of this operation. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`audience`** `object` **REQUIRED** Specifies the email address you want to perform tag operations against. Must contain a single `email_address` key. **OBJECT PROPERTIES** - **`email_address`** `string` **REQUIRED** The email address you want to modify tags for. Accepts a single string value representing an email address. Example: `name@example.com` - **`remove`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Removes the specified tags from the channel. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`set`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Assigns a list of tags exactly. Any previously set tags that are not in this current list are removed. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. **Responses** **`200`** Returns OK for success. If a tag request is partially valid, i.e., at least one tag group exists and is active, a 200 will be returned with a warning in the response about the tag groups that failed to update. The tag groups listed in the warning will be CSV-formatted. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/email/tags HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "email_address": "name@example.com" }, "add": { "my_fav_tag_group1": ["tag1", "tag2", "tag3"], "my_fav_tag_group2": ["tag1", "tag2", "tag3"], "my_fav_tag_group3": ["tag1", "tag2", "tag3"] } } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); EmailTagRequest request = EmailTagRequest.newRequest(); emailTagRequest.addEmailChannel("name@example.com") .addTags("my_fav_tag_group1", ImmutableSet.of("tag1", "tag2", "tag3")) .addTags("my_fav_tag_group2", ImmutableSet.of("tag1", "tag2", "tag3")) .addTags("my_fav_tag_group3", ImmutableSet.of("tag1", "tag2", "tag3")); Response response = client.execute(request); ``` ```python from urbanairship import ( BearerTokenClient, EmailTags ) client = BearerTokenClient( app_key='', token='' ) # replaces all existing tags on an email channel email_tags = EmailTags(airship=client, address='name@example.com') email_tags.set(group='my_tag_group', tags=['one', 'two', 'three']) email_tags.send() # adds and removes tags from an email channel email_tags = EmailTags(airship=client, address='name@example.com') email_tags.remove(group='my_tag_group', tags=['one', 'two', 'three']) email_tags.add(group='my_tag_group', tags=['some', 'new', 'tags']) email_tags.send() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') email_tags = UA::EmailTags.new(client: airship) #set an audience email_tags.set_audience(email_address: 'name@example.com') #add a tag email_tags.add(group_name: 'my_fav_tag_group1', tags: 'tag2') #remove a tag email_tags.remove(group_name: 'my_fav_tag_group1', tags: 'tag1') email_tags.send_request ``` --- ## Named Users tags {#modifynamedusertags} Add, remove, or set tags on a Named User. A single request body may contain add and/or remove objects or a single set field. At least one of the add, remove, or set objects must be present in a request. [Jump to examples ↓](#modifynamedusertags-examples) ### `POST /api/named_users/tags` {{< important >}} A tag must be < 128 characters. A request with one or more tags longer than 128 characters will return a 400 response. We support up to 1,000 tags per Named User. Adding more than 1,000 tags per Named User can cause latency and service interruptions. We strongly recommend removing unused tags whenever possible, and using Custom Events when appropriate. Please [contact Support](https://support.airship.com/) if you believe your use case requires more than 1,000 tags per Named User, and they will help you find an alternative. {{< /important >}} **Security:** - [basicAppAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAppAuth) - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): nu **Request body** **Content-Type:** `application/json` - **`add`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Add the list of tags to the Named User(s), but do not remove any. If the tags are already present, they are not modified. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`audience`** `object` **REQUIRED** The Named User(s) you want to associate/disassociate tags with. **OBJECT PROPERTIES** - **`named_user_id`** `array[string]` Min items: 1, Max items: 1000 - **`remove`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Remove the list of tags from the Named User(s), but do not remove any others. If the tags are not currently present, nothing happens. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`set`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Set these tags for the audience; any tags previously associated with the audience tags that are not in this current list are removed. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. **Responses** **`200`** If a tag request is partially valid, i.e., at least one tag group exists and is active, a 200 will be returned with a warning in the response about the tag groups that failed to update. The tag groups listed in the warning will be CSV-formatted. Response body: **Content-Type:** `application/json` - **`ok`** `boolean` **REQUIRED** Set to `true` when status code is `200`. - **`tag_warnings`** `string` Warnings encountered when processing tags for this Named User. **`400`** Parsing or validating the request failed. You will see this error if the same tag is present in both the add and remove fields. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`406`** Return when the client requests a version of the API that cannot be satisfied, because no compatible version is currently deployed. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/named_users/tags HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "named_user_id": [ "user-1", "user-2", "user-3" ] }, "add": { "crm": [ "tag1", "tag2", "tag3" ], "loyalty": [ "tag1", "tag4", "tag5" ] }, "remove": { "loyalty": [ "tag6", "tag7" ] } } ``` ```http HTTP/1.1 200 OK Content-Type: application/vnd.urbanairship+json; version=3 { "ok": true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); NamedUserTagRequest request = NamedUserTagRequest.newRequest() .addNamedUsers("user-1", "user-2", "user-3") .addTags("crm", ImmutableSet.of("tag1", "tag2", "tag3")) .addTags("loyalty", ImmutableSet.of("tag1", "tag4", "tag5")) .removeTags("loyalty", ImmutableSet.of("tag6", "tag7")); Response response = client.execute(request); ``` ```python from urbanairship import ( BasicAuthClient, NamedUser ) client = BasicAuthClient( key='', secret='' ) named_user = NamedUser(airship=client, named_user_id='user-1') resp1 = named_user.tag( group='loyalty', add=['tag2', 'tag3', 'tag4'], remove='tag1' ) resp2 = named_user.tag( group='crm', set=['tag5', 'tag6'] ) ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') named_user_tags = UA::NamedUserTags.new(client: airship) named_user_ids = ['user-1', 'user-2', 'user-3'] named_user_tags.set_audience(user_ids: named_user_ids) named_user_tags.add(group_name: 'crm', tags: ['tag1', 'tag2', 'tag3']) named_user_tags.remove(group_name: 'loyalty', tags: ['tag6', 'tag7']) named_user_tags.send_request ``` --- ## Open channel tags {#modifyopenchanneltags} Manipulate a single open channel’s tags. Open channels are identified by `address`, not by their `channel_id`. [Jump to examples ↓](#modifyopenchanneltags-examples) ### `POST /api/channels/open/tags` {{< important >}} A tag must be < 128 characters. A request with one or more tags longer than 128 characters will return a 400 response. We support up to 1,000 tags per channel. Adding more than 1,000 tags per channel can cause latency and service interruptions. We strongly recommend removing unused tags whenever possible, and using Custom Events when appropriate. Please [contact Support](https://support.airship.com/) if you believe your use case requires more than 1,000 tags per channel, and they will help you find an alternative. {{< /important >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** **Content-Type:** `application/json` - **`add`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Adds the specified tags to the channel. Tags that are already present are not modified/removed as a result of this operation. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`audience`** `object` **REQUIRED** The request body containing an address and `open_platform_name`. **OBJECT PROPERTIES** - **`address`** `string` **REQUIRED** Where notifications sent to this `channel_id` will be sent. Examples: email address, phone number. If missing, `channel_id` must be present. The `address` is one-to-one with the `channel_id`. New addresses on existing channels will overwrite old associations. Example: `new_email@example.com` - **`open_platform_name`** `string` **REQUIRED** An alphanumeric string that must be the name of a pre-created open platform object. Min length: 1, Max length: 128 Example: `twitter` - **`remove`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Removes the specified tags from the channel. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`set`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Assigns a list of tags exactly. Any previously set tags that are not in this current list will be removed. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. **Responses** **`200`** Returns OK for success. If a tag request is partially valid, i.e., at least one tag group exists and is active, a 200 is returned with a warning in the response about the tag groups that failed to update. The tag groups listed in the warning will be CSV-formatted. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/open/tags HTTP/1.1 Authorization: Basic Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "address": "Number Four", "open_platform_name": "cylon" }, "add": { "my_fav_tag_group1": ["tag1", "tag2", "tag3"], "my_fav_tag_group2": ["tag1", "tag2", "tag3"], "my_fav_tag_group3": ["tag1", "tag2", "tag3"] } } ``` ```http HTTP/1.1 200 Accepted Content-Type: application/vnd.urbanairship+json; version=3 { "ok":true } ``` ```java UrbanAirshipClient client = UrbanAirshipClient.newBuilder() .setKey("") .setSecret("") .build(); OpenChannelTagRequest openChannelTagRequest = OpenChannelTagRequest.newRequest() .addOpenChannel("Number Four","cyclon") .addTags("CRM_Delux", Set.of("tag1","tag2")) .removeTags("CRM_Delux", Set.of("tag3","tag4")); Response response = client.execute(openChannelTagRequest); ``` ```python from urbanairship import ( BasicAuthClient, OpenChannel ) client = BasicAuthClient( key='', secret='' ) channel = OpenChannel(airship=client) channel.address = 'Number Four' channel.open_platform = 'cylon' channel.tags = ['tag1', 'tag2', 'tag3'] response = channel.update() ``` ```ruby require 'urbanairship' UA = Urbanairship airship = UA::Client.new(key: '', secret: '') open_channel = UA::OpenChannel.new(client: airship) open_channel.opt_in = true open_channel.address = 'Number Four' open_channel.open_platform = 'cylon' open_channel.channel_id = 'df6a6b50-9843-0304-d5a5-743f246a4946' open_channel.tags = ['tag1', 'tag2', 'tag3'] open_channel.update(set_tags: true) ``` --- ## SMS tags {#modifysmschanneltags} Add, remove, or set tags for a single SMS channel. [Jump to examples ↓](#modifysmschanneltags-examples) ### `POST /api/channels/sms/tags` {{< important >}} A tag must be < 128 characters. A request with one or more tags longer than 128 characters will return a 400 response. We support up to 1,000 tags per channel. Adding more than 1,000 tags per channel can cause latency and service interruptions. We strongly recommend removing unused tags whenever possible, and using Custom Events when appropriate. Please [contact Support](https://support.airship.com/) if you believe your use case requires more than 1,000 tags per channel, and they will help you find an alternative. {{< /important >}} **Security:** - [basicAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-basicAuth) - [bearerAuth]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-bearerAuth) - [oauth2Token]({{< ref "/developer/rest-api/ua/introduction/" >}}#security-oauth2Token): chn **Request body** A single request body can contain an `add` and/or `remove` field or a single `set` field. One or more of the `add`, `remove`, or `set` keys must be present in the request. **Content-Type:** `application/json` - **`add`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Adds the specified tags to the channel. Tags that are already present are not modified/removed as a result of this operation. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`audience`** `object` **REQUIRED** Specifies the MSISDN and sender you want to perform tag operations against. **OBJECT PROPERTIES** - **`msisdn`** `string` The mobile phone number corresponding to the SMS channel. Must be numeric characters only, without leading zeros. 15 digits maximum. Max length: 15 - **`sender`** `string` A long or short code the app is configured to send from. For example, `12345`. - **`remove`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Removes the specified tags from the channel. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. - **`set`** `object` <[Tag Group object]({{< ref "/developer/rest-api/ua/schemas/tags/" >}}#taggroupobject)> Assigns a list of tags exactly. Any previously set tags that are not in this current list are removed. Tags belong to Tag Groups. Tag Groups appear within the `tags` object for a Named User or the `tag_groups` object for a channel. See also [Device Properties](/docs/reference/data-collection/device-properties/) ``ua_`` is a reserved prefix for Airship-specific tag groups. A Tag Group has two parts: a "name" string of 1-128 characters, and an array of tags, containing 0-100 tags. Each tag in the array is also a string consisting of 1-128 characters. **Responses** **`200`** Returns OK for success. If a tag request is partially valid, i.e., at least one tag group exists and is active, a 200 will be returned with a warning in the response about the tag groups that failed to update. The tag groups listed in the warning will be CSV-formatted. Response body: **Content-Type:** `application/vnd.urbanairship+json; version=3` [OK response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#okresponseobject) **`400`** There was a parsing or validation error in the request. Bad Request errors typically include `path` and `location` in the response to help you find the cause of the error. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`401`** Authentication information (the app key and secret or bearer token) was either incorrect or missing. Response body: **Content-Type:** `text/plain` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **`403`** Authentication was correct, but the user does not have permission to access the requested API, e.g., if the feature in question is not included in your pricing plan. Response body: **Content-Type:** `application/json` [Error response]({{< ref "/developer/rest-api/ua/schemas/responses/" >}}#error) **Examples** *Example* ```http POST /api/channels/sms/tags HTTP/1.1 Authorization: Bearer Accept: application/vnd.urbanairship+json; version=3 Content-Type: application/json { "audience": { "sender": "12345", "msisdn": "15035556789" }, "add": { "my_fav_tag_group1": ["tag1", "tag2", "tag3"], "my_fav_tag_group2": ["tag1", "tag2", "tag3"], "my_fav_tag_group3": ["tag1", "tag2", "tag3"] } } ``` ---