Create or update one or more people (merge)
The merge Ortto endpoint of the person entity is used to create or update one or more person records in Ortto’s customer data platform (CDP).
This page provides descriptions of this endpoint’s:
- the response payload.
HTTP method and request resource
POST https://api.ap3api.com/v1/person/merge
NOTE: Ortto customers who have their instance region set to Australia or Europe will need to use specific service endpoints relative to the region:
- Australia: https://api.au.ap3api.com/
- Europe: https://api.eu.ap3api.com/
For example: https://api.eu.ap3api.com/v1/<entity/endpoint>
All other Ortto users will use the default service endpoint (https://api.ap3api.com/).
Path and query parameters
This endpoint takes no additional path and/or query parameters.
Headers
This endpoint requires a custom API key and content type (application/json for the request body) in the header of the request:
X-Api-Key: CUSTOM-PRIVATE-API-KEYContent-Type: application/json
Request body
The request body consists of a JSON object whose valid elements are listed in the table below.
The following JSON object is an example of field and object data that Ortto can recognize to create or update one or more person records in your Ortto account’s CDP.
Example create/update people request body in Ortto’s CDP
json
{ "people": [ { "fields": { "str::first": "Chris", "str::last": "Smith", "str::email": "chris.smith@example.com", "str:cm:job-title": "Technician" }, "location": { "source_ip": "119.18.0.218" } }, { "fields": { "str::first": "Alex", "str::email": "alex@example.com" }, "location": { "source_ip": "119.18.0.218" } } ], "async": true, "merge_by": ["str::email"], "merge_strategy": 2, "find_strategy": 0, "suppression_list_field_id": "str::email" }
IMPORTANT: If you are sending a large number of synchronous ("async": false) API updates using a merge key (e.g. "merge_by": ["str::email"]) this can end up hitting a concurrency limit and your API requests may start to fail.
To avoid this, and to speed up the processing of the API requests, we recommend using asynchronous ("async": true) updates where possible, or if the person ID of the contact is known, merging by person_id instead, as it’s a guaranteed unique identifier of the contact and so no lookup request is needed to search through all contacts. See below for an example of merging by person ID.
TIP: You can provide up to three fields in the merge_by array.
Merge_by array
If you provide any fields in the merge_by array, only those fields will be used for merging.
If you do not send any fields in the merge_by array, we will fall back to using the unique identifier list defined in your Custom API data source.
Check against other field

You can replicate the Check against another field option from the account unique identifiers in your API payload by using the following syntax:
json
"merge_by_alt_fields": { "str::email": ["{your alt email field id}"] }
Learn more about the check against another field option.
Merging person records using a person’s ID
If merging by a person’s ID, then person_id must be the only field in the merge_by array.
Example create/update people and merge by a person’s ID
json
{ "people": [ { "fields": { "str::first": "Jack", "str::last": "Skellington", "str::person_id": "00647687d2e43b25a0261f00" } }, { "fields": { "str::first": "Sally", "str::last": "O'Hara", "str::person_id": "00647687d2f43b25b0261f01" } } ], "async": false, "merge_by": ["str::person_id"], "merge_strategy": 2, "find_strategy": 1 }
Valid request body elements
The following table lists all valid request body elements (arrays, objects, or fields), which are available to this endpoint.
Element | Type | Description |
|---|---|---|
|
| The
Between 1 to 100 people (each as individual objects of this |
→ | Object containing person field members | The object containing the fields for a person being created or updated in your Ortto account’s CDP. This person is either created or updated in Ortto’s CDP based on these criteria:
|
→ | Object containing location field data | The |
→ |
| Each |
→ |
| Each
Therefore, a construct like:
would result in Tag2 and Tag3 being applied to this person. Tag1 would be removed if it had already been applied to this person. Otherwise, if Tag1 were not applied to this person, the tag’s explicit removal (as depicted in this code example), has no effect. |
→ | Object containing person field members | The |
|
| When set to IMPORTANT: If you are sending a large number of synchronous ( To avoid this, and to speed up the processing of the API requests, we recommend using asynchronous ( |
|
| The When the value of the person field member (determined by the relevant These values respectively override the default person fields associated with the custom API key submitted in this request. These default field values are defined by the Merge strategy associations configured for this custom API key.
If a NOTE: If merging by a person’s ID, then`person_id` must be the only field in the |
|
| When the |
|
| The Find strategy determines how the |
|
| The For example, this is useful when you want to update the email address for a contact by their data source ID (in this example, a Chargebee customer ID):
NOTE: When using. a merge key that is read-only (such as the Chargebee customer ID above: |
|
| The The value of this setting should be the field that contains the email address you want to compare against the suppression list, which in most cases will be the default email address, for example:
When a contact is skipped because their email address is suppressed, you will get this response:
|
NOTE: When updating a contact's multi-select field values, if the new values are intended to replace existing values, the field must first be cleared.
Learn more about clearing and setting a person's field values.
About empty values
When you use a filter to search for people, the Has any value filter option will find matches for activity attribute and field values that have a value of 0 or "" (empty string). However, Has any value won’t find attribute or field values that are null.
You can set values according to your needs by updating a person’s data using this API endpoint (v1/person/merge). To:
- Include an empty value in a search: set an existing
nullto0or"". - Exclude an empty value from search: set an existing
""or0value tonull.
For example, updating a person’s field value to exclude it from search can look like this:
json
"people": [ { "fields": { "str::first": "John", "str::last": "Apple", "str::email": "japple@email.com", "str:cm:job-title": null }
Person fields
In Ortto, a person field:
- contains the data for a specific piece of information (i.e. field) about each person in Ortto’s CDP,
- is referenced via the Ortto API using a specific ID format,
- could be a built in Ortto field or a custom field you have defined yourself (which also has its own ID format), and
- is defined as a member for each person (within their respective
fields : { … }object) submitted in the request to this endpoint.
The following built-in person fields are accessible through Ortto’s API when creating or updating people in the CDP.
Field name | Example | Description |
|---|---|---|
First name |
| A string whose value is this person’s first name. |
Last name |
| A string whose value is this person’s last name. |
Person ID |
| A string value representing a unique identifier for the person’s CDP record. |
Phone number |
or
| A phone number field can be provided in one of two ways: 1 - an object of two members consisting of valid country code digits ( 2 - An object of two members consisting of the phone number ( |
| A string whose value is this person’s email address. This person field and its value is commonly used as the main | |
City |
| A geographical data object consisting of a member |
Country |
| A geographical data object consisting of a member |
Birthday |
| A date object consisting of members |
Region |
| A geographical data object consisting of a member |
Postal |
| A string whose value is this person’s current postal code. |
External ID |
| A string whose value is any ID used to uniquely identify this person. This value is mandatory if the email field is not provided in the containing |
GDPR |
| A boolean value where |
Email subscription permission |
| A boolean value where |
Custom context message for the email unsubscribe action |
| A string value that allows you to customize the default activity context message from Unsubscribed via API to something else, when setting the email subscription permission to |
Custom context message for the email subscribe action |
| A string value that allows you to customize the default activity context message from Subscribed via API to something else, when setting the email subscription permission to |
SMS subscription permission |
| A boolean value where |
Custom context message for the SMS subscribe action |
| A string value that allows you to customize the default activity context message from Subscribed via API to something else, when setting the SMS subscription permission to |
Custom context message for the SMS unsubscribe action |
| A string value that allows you to customize the default activity context message from Unsubscribed via API to something else, when setting the SMS subscription permission to |
Language |
| A string which determines the person’s preferred language. This can be used to present email campaigns in the person’s preferred language (where supported) using Ortto’s multi-language feature. See a list of available language values at List of languages. |
Allow tracking |
| A boolean value where If this person field is not specified in the request, the value remains unset (no value), meaning the person hasn't yet been asked or hasn't made a choice. Learn more about subscriber-level email tracking permission. |
Allow tracking context |
| A string value that allows you to describe why or how this person's Allow tracking value was set (e.g. via a capture form, preference center, footer link, CSV import, or API update). |
FCM iOS push notification token |
| If a user has already given push permission to your mobile app before implementing Ortto's SDK, you can use these fields to submit the notification token to Ortto so it can be re-used for sending Ortto's push notifications without having to ask the customer for permission again. |
APN iOS push notification token |
| |
Android push notification token |
|
Person field ID format
Each person field is referenced by an ID.
Since Ortto integrates with many third-party products, references to person fields in Ortto’s CDP are both strongly-typed and namespace-specific. Therefore, each person field’s ID is based on the format:
type:namespace:field-name
For:
- Ortto’s own built-in person fields, the
namespacevalue is unnecessary and is omitted. Hence, these built-in fields are referenced by an ID based on the format:type::field-name
- Up to 100 custom fields can be added to an Ortto account/instance.The
field-namefor custom fields is typically based on their configured names converted to kebab-case.type:cm:field-name
NOTE:
- Up to 150 fields can be sent in a single request
- The total number of custom fields you can have in an Ortto account/instance depends on your plan.
- The
field-namefor custom fields is typically based on their configured names converted to kebab-case.
Person field type abbreviations
The following person field type abbreviations are used to form the first part (type) of each person field’s ID for built-in fields:
Field type abbreviation | Type of value |
|---|---|
| Boolean |
| Date (object) |
| Geographical data (object) |
| Integer. For internal operations and calculations, the Ortto API treats decimal values as integers multiplied by 1,000. This is done to preserve the precision of values resulting from these calculations. Note: Integers are processed as |
| Phone number (object) |
| String |
Merge strategy
The merge strategy determines how a person’s existing field values are merged.
When the merge_by member value (and its corresponding person field member value) submitted in this request determines that an existing person’s record in Ortto’s CDP will be updated, then one of the following merge_strategy values in the request determines how the person’s existing field values are merged:
merge_strategy (integer) | Strategy | Description |
|---|---|---|
1 | Append only | Using this strategy, all fields with existing values in Ortto’s CDP are not changed. Ortto only adds new data (for fields without a value).
For example, assuming you have a custom field
|
2 | Overwrite existing (default) | Using this strategy, any person fields specified in the request are updated in Ortto’s CDP, even when existing values are present, and hence are overwritten.
A person’s field in the CDP can be cleared by specifying the corresponding person field’s value in the request as
Any person fields which are not specified in the request are not cleared (and retain their value) in the person’s CDP record. |
3 | Ignore | Using this strategy, no updates are applied to the existing person’s record in Ortto’s CDP, but a new person will be created if it doesn’t exist. If you do not wish to create a new person you need to provide the TIP: Use this merge strategy to enforce only adding new people to the CDP, leaving existing people’s records untouched. |
Find strategy
The find strategy determines how the merge_by fields are used to detect an existing person match.
The find strategy is only relevant if you have 2 or more merge_by fields provided. When you have only 1 field, this setting makes no difference to the outcome. When 2 or more merge_by fields are provided, the find_strategy value determines how we utilise the fields in detecting an existing person match:
find_strategy (integer) | Strategy | Description |
|---|---|---|
0 | Any (default) | Using this strategy, all
|
1 | Next only if previous empty | Using this strategy, the first
If a match is not found using the first field, there are 2 scenarios that can happen:
|
2 | All | Using this strategy, all
If only one of the |
Key combinations to achieve different merge strategies
When you use Ortto's user interface (UI) to import contacts, such as when you connect a data source like Salesforce or Segment, or perform a CSV import, you will be presented with a number of options for the merge strategy and merge key strategies.

If you are creating or merging contacts via the v1/person/merge endpoint, the merge strategies presented in the UI are achieved according to the merge_strategy and skip_non_existing values you use.
The equivalent combinations are:
- Import and merge new data only: “merge_strategy”: 1, “skip_non_existing”: false
- Import and merge new data for existing records only: “merge_strategy”: 1, “skip_non_existing”: true
- Import and overwrite any data that exist (recommended): “merge_strategy”: 2, “skip_non_existing”: false
- Import and overwrite any data that exist for existing records “merge_strategy”: 2, “skip_non_existing”: true
- Import new records only: “merge_strategy”: 3, “skip_non_existing”: false
The merge key strategy is determined by the identifiers you set at merge_by and the find_strategy value.
The equivalent merge key strategies are:
- Match only if previous merge key is empty: “find_strategy”: 1
- Merge with any key match: “find_strategy”: 0