# 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 <application authorization string>
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("<app key>")
        .setSecret("<master secret>")
        .build();
        
AttributeListsCreateRequest attributeListsCreateRequest = AttributeListsCreateRequest.newRequest("ua_attributes_list")
        .setDescription("ua_attributes_list")
        .addExtra("filename", "attributes.csv")
        .addExtra("source","crm");

Response<GenericResponse> response = client.execute(attributeListsCreateRequest);

```

```python
from urbanairship import (
    BasicAuthClient, AttributeList
)

client = BasicAuthClient(
    key='<app_key>',
    secret='<master_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 <application authorization string>
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("<app key>")
        .setSecret("<master secret>")
        .build();

AttributeListsErrorsRequest attributeListsErrorsRequest = AttributeListsErrorsRequest.newRequest("ua_attributes_list");
Response<String> response = client.execute(attributeListsErrorsRequest);

```

```python
from urbanairship import (
    BasicAuthClient, AttributeList
)

client = BasicAuthClient(
    key='<app_key>',
    secret='<master_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 <master authorization string>
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='<app_key>',
    secret='<master_secret>'
)

listing = AttributeList.list(airship=client)

listing.json()

```

```java
UrbanAirshipClient client = UrbanAirshipClient.newBuilder()
        .setKey("<app key>")
        .setSecret("<master secret>")
        .build();

AttributeListsListingRequest attributeListsListingRequest = AttributeListsListingRequest.newRequest();
Response<AttributeListsListingResponse> 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              | <ul><li>`msisdn` (numeric and no leading 0) </li><li>`sms_sender` (numeric, e.g., `1234`)</li></ul> |
| MMS              | <ul><li>`msisdn` (numeric and no leading 0) </li><li> `sms_sender` (numeric, e.g., `1234`)</li></ul> |

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           | <ul><li>`ua_transactional_opted_in` (UTC Timestamp) </li><li> `ua_commercial_opted_in` (UTC Timestamp)</li></ul> |


[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 <application authorization string>
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 <application authorization string>
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='<app_key>',
    secret='<master_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 <application authorization string>
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='<app_key>',
    secret='<master_secret>'
)

attribute_list = AttributeList(
  client=client, 
  list_name="ua_attributes_list",
  description="example list", 
)

attribute_list.upload(file_path="path/to/sms_file.csv")

```

---

