Profiles are usually created with events with the Events API. You can also create them separately with the Profiles API.

Each profile is associated with a Zendesk user when it's created. To learn more, see How profiles are associated with Zendesk users.

Profiles are created synchronously. You'll get a response with a "201" status if a profile was created successfully. You'll get a "202" if an event with a corresponding profile is created successfully.

This article includes curl and Python examples. The Python examples use Python 3.6 or greater and the requests library.

How profiles are created

When Zendesk receives a request to create a profile, first it checks for any existing profile that has a matching combination of source, type, and identifier. See Anatomy of a profile. If it finds a match, it replaces the existing profile with the new profile. If no match is found, it creates the profile.

Because the existing profile is replaced, any data that's not included in the new version is lost. You can make a preliminary request to search the profiles for the same source-type-identifier combination. See Accessing profiles. If found, you can abort the request to create it or you can patch it. See Patching a profile.

Understanding the identifier path parameter

In the Profiles API, the request paths to create profiles have a required identifier parameter that takes an identifier query:

  • PUT /api/v2/user_profiles?identifier={identifier_query}
  • PUT /api/v2/users/{user_id}/profiles?identifier={identifier_query}

An identify query specifies the profile's source and type as well as an identifier for the person associated with the profile. Example:

identifier=coolbikes:rider:email:[email protected]

To learn more, see Using identifier queries with profiles.

The identifier query plays two roles when creating a profile. First, it defines the source and type of the new profile. In the example above, the profile's source is "coolbikes" and its type is "rider".

Second, it checks for a duplicate profile before creating the profile. The identifier query searches for a profile that has the same source-type-identifier combination as the profile you're attempting to create. If a matching combination is found, the API replaces the existing profile with yours. If no match is found, it creates the profile.

To check for duplicate profiles, use one of the identifiers in the profile object as the identifier in the query. In the example above, you should use email:[email protected] in the query.

How profiles are associated with Zendesk users

Each profile is associated automatically with a Zendesk user when it's created. You don't need to specify a Zendesk user id in the profile object (though you can if you want). On profile creation, the API looks for a Zendesk user with a Zendesk identity such as an email address or phone number that matches an identifier in the new profile. If the API finds a Zendesk user, it associates the profile with the user. If the API can't find a Zendesk user who shares any of the identifiers, it creates an anonymous Zendesk user with the same name as the profile name, and associates the profile with the user.

The API looks for Zendesk users only if the profile identifiers has one of the following identifier types:

  • "email"
  • "external_id"
  • "phone_number"
  • "facebook"
  • "twitter"

These are known in the API as standard identifier types.

The API will try to match the value of the identifier type with the value of the corresponding user identity type in Zendesk. For example, the API will look for a Zendesk user if an identifier has a type value of "email":

"identifiers": [  {    "type": "email",    "value": "[email protected]"  }]

The API won't look for a match if the profile doesn't have any standard identifier types. Example:

"identifiers": [  {    "type": "e-mail",    "value": "[email protected]"  }]

To check for existing Zendesk users, make sure to use standard identity types. For example, use "email" instead of "e-mail" or "email_address". Otherwise a new anonymous user will be created.

Any standard identifier type defined in the profile is added as an identity in the Zendesk user record if the identity doesn't already exist. You can look up a user's identities in Zendesk with the User Identities API:

curl https://{subdomain}.zendesk.com/api/v2/users/{user_id}/identities.json \  -v -u {email_address}:{password}

Creating profiles with events

The event tracking endpoint in the Events API expects a profile object with each event. You can use the following endpoint to track events:

POST /api/v2/user_profiles/events

The request body takes both an event object and a profile object. The profile object must specify one or more identifiers as well as optional attributes about the person. The profile object must also specify a source and a type.

See Tracking events in this guide.

Example

Data

Request body in event.json file:

{  "profile": {    "source": "coolbikes",    "type": "rider",    "identifiers": [      {        "type": "email",        "value": "[email protected]"      }    ]  },  "event": {    "source": "coolbikes",    "type": "bike_rental_booked",    "description": "A CoolBike rental has been booked",    "properties": {      "booking_date": "2020-02-01",      "return_date": "2020-02-05"    }  }}

curl request

curl https://coolbikes.zendesk.com/api/v2/user_profiles/events \  -d @event.json \  -H "Accept: application/json" \  -H "Content-Type: application/json" \  -v -u devs@coolbikes.com:t1retube5 -X POST

Python request

import json
import requests
with open('event.json', mode='r') as f:    event = json.load(f)
url = 'https://coolbikes.zendesk.com/api/v2/user_profiles/events'headers = {'Content-Type': 'application/json'}credentials = '[email protected]', 't1retube5'response = requests.post(url, json=event, auth=credentials, headers=headers)if response.status_code != 202:    print(f'{response.status_code}: {response.text}')else:    print(response.json())

Response

Status 202
{  "status":"received",  "user_id":"81123613",  "profile_id":"01E1G0NJSQPNPZRV096JXKXFAA"}

Creating separate profiles

You can create profiles separately from events with the following PUT request:

PUT /api/v2/user_profiles?identifier={identifier_query}

The request sends profile data in both the request path and the request body.

Request path

The request path takes a required identifier parameter that specifies an identifier query. Example:

identifier=coolbikes:rider:email:[email protected]

The first two items in the identifier query, coolbikes and rider, define the new profile's source and type properties. The last two items, email and [email protected], should specify one of the identifiers in the profile in the request body. For more information, see Using identifier queries with profiles.

Request body

The request body takes a profile object that specifies one or more identifiers as well as optional attributes about the person:

{  "profile": {    "identifiers": [      {        "type": "email",        "value": "[email protected]"      },      ...    ],    "attributes": {      "my_property_name": "some_value",      ...    }  }}

The profile's source and type properties are not defined in the request body. You define these values in the request path.

Example

Data

  • Request path parameter:

    identifier=coolbikes:rider:email:jdoe@example.com
  • Request body in profile.json file:

    {    "profile": {      "identifiers": [        {          "type": "email",          "value": "[email protected]"        }      ],      "attributes": {        "favorite_color": "red",        "saddle_height": "85cm"      }    }  }

curl request

curl "https://coolbikes.zendesk.com/api/v2/user_profiles?identifier=coolbikes:rider:email:[email protected]" \  -d @profile.json \  -H "Content-Type: application/json" \  -v -u devs@coolbikes.com:t1retube5 -X PUT

Python request

import json
import requests

identifier_query = 'coolbikes:rider:email:[email protected]'with open('profile.json', mode='r') as f:    profile = json.load(f)
url = 'https://coolbikes.zendesk.com/api/v2/user_profiles'params = {'identifier': identifier_query}headers = {'Content-Type': 'application/json'}credentials = '[email protected]', 't1retube5'response = requests.put(url, params=params, json=profile, headers=headers, auth=credentials)if response.status_code != 201:    print(f'{response.status_code}: {response.text}')else:    print(response.json())

Response

Status 201
{  "profile": {    "id":"01E06HXMJ8RJ6C0MR142D6FBSA",    "user_id":"81123613",    "source":"coolbikes",    "type":"rider",    "name":"[email protected]",    "attributes":{      "favorite_color":"red",      "saddle_height":"85cm"    },    "created_at":"2020-02-03T22:14:48Z",    "updated_at":"2020-02-20T01:20:28Z",    "identifiers":[      {        "type":"email",        "value":"[email protected]"      }    ]  }}

Creating separate profiles for Zendesk users

If you know the Zendesk user id of the person, you can associate a new profile directly to the user with the following API request:

PUT /api/v2/users/{user_id}/profiles?identifier={identifier_query}

Note: You can also associate a new profile directly to a user when creating a separate profile by specifying the person's Zendesk user id as the value of the profile's user_id property.

You can use the Zendesk Users API to lookup a user id.

The request sends profile data in both the request path and the request body.

A collision with an existing Zendesk user is possible with this request. The request will return an error. See Making requests with Zendesk user ids in "How profiles affect existing data".

Request path

The request path takes a required identifier parameter that specifies an identifier query. Example:

identifier=coolplanes:pilot:email:[email protected]

The first two items in the identifier query, coolplanes and pilot, define the new profile's source and type properties. The last two items, email and [email protected], should specify one of the identifiers in the profile in the request body.

See Understanding the identifier path parameter.

Request body

Request body in profile.json file:

{  "profile": {    "identifiers": [      {        "type": "email",        "value": "[email protected]"      },      ...    ],    "attributes": {      "my_property_name": "some_value",      ...    }  }}

The profile's source and type properties are not defined in the request body. You define these values in the request path.

Example

Data

  • Zendesk user id:

    "81123613"

  • Request path parameter:

    identifier=coolplanes:pilot:email:jdoe@example.com
  • Request body in profile.json file:

    {    "profile": {      "identifiers": [        {          "type": "email",          "value": "[email protected]"        }      ],      "attributes": {          "certification": "sport pilot"      }    }  }

curl request

curl "https://coolplanes.zendesk.com/api/v2/users/81123613/profiles?identifier=coolplanes:pilot:email:[email protected]" \  -d @profile.json \  -H "Content-Type: application/json" \  -v -u devs@coolplanes.com:t1retube5 -X PUT

Python request

import json
import requests

user_id = '81123613'identifier_query = 'coolplanes:pilot:email:[email protected]'with open('profile.json', mode='r') as f:    profile = json.load(f)
url = f'https://coolplanes.zendesk.com/api/v2/users/{user_id}/profiles'params = {'identifier': identifier_query}headers = {'Content-Type': 'application/json'}credentials = '[email protected]', 't1retube5'response = requests.put(url, params=params, json=profile, auth=credentials, headers=headers)if response.status_code != 201:    print(f'{response.status_code}: {response.text}')else:    print(response.json())

Response

Status 201
{  "profile":{    "id":"01E1J6EG8BR8BZBAKYKH092TX4",    "user_id":"81123613",    "source":"coolplanes",    "type":"pilot",    "name":"[email protected]",    "attributes":{      "certification":"sport pilot"    },    "created_at":"2020-02-20T21:00:53Z",    "updated_at":"2020-02-20T21:00:53Z",    "identifiers":[      {        "type":"email",        "value":"[email protected]"      }    ]  }}