Batch-upsert preference records for multiple users.
Rate Limits
- 10000 preference records per organization per minute (default).
- This limit can be adjusted per organization upon request.
Note: Unlike other Preferences API endpoints, the upsert preferences endpoint has a default rate limit of 10,000 preference records per organization per minute, not 10,000 requests per minute.
This means that you can update up to 10,000 preference records in batches of any size (up to 100 records per batch) within a minute.
For example, you could update 100 records in a single request, or 10 records in each of 10 requests, and both would consume the same portion of your rate limit (100 records).
Rate Limiting Headers
X-RateLimit-Limit: The maximum number of requests allowed in the current window.X-RateLimit-Remaining: The number of requests remaining in the current window.X-RateLimit-Reset: The time at which the current rate limit window resets in ISO 8601 format.Retry-After: (on 429) The number of seconds to wait before making a new request.
PUT
/v1/preferencesIn your request headers, pass authorization: Bearer <<token>>.
If you're self-hosting Sombra, also add the request header x-sombra-authorization: Bearer <<sombraInternalKey>>. You can read more about request authorization here.
Requires scope:
Modify User Stored Preferences
authorizationstringAn API key generated from the Transcend dashboard: https://app.transcend.io/infrastructure/api-keys. |
x-sombra-authorizationstringThe Sombra internal key. This header is only needed for self-hosted Sombra gateways. See https://docs.transcend.io/docs/dsr-automation/api-integration/authentication#authenticating-to-sombra |
content-typestringSpecify content-type: application/json for a JSON response from the Transcend API. |
application/json
recordsarray<object>(required)The list of user preferences records to update. |
skipWorkflowTriggersbooleandefault:falseWhether to skip triggering workflows associated with the purpose change event. |
Request Body Examples
Query for upserting user preferences, identifiers and triggering associated workflows:
{
"records": [
{
"partition": "ea3a0845-694e-4820-9d51-50c7d0a23467",
"timestamp": "2023-05-11T19:32:31.707Z",
"identifiers": [
{
"name": "email",
"value": "no-track@example.com"
},
{
"name": "phone",
"value": "+11234567890"
}
],
"purposes": [
{
"purpose": "Advertising",
"enabled": true
},
{
"purpose": "Analytics",
"enabled": false
},
{
"purpose": "ProductUpdates",
"enabled": true,
"preferences": [
{
"topic": "Frequency",
"choice": {
"selectValue": "Weekly"
}
},
{
"topic": "Channel",
"choice": {
"selectValues": [
"Email",
"Sms"
]
}
},
{
"topic": "Unsubscribe",
"choice": {
"booleanValue": true
}
}
],
"workflowSettings": {
"isSilent": true,
"attributes": [
{
"key": "Source",
"values": [
"Mobile iOS App"
]
}
]
}
}
],
"metadata": [
{
"key": "version",
"value": "1.0.0"
}
]
},
{
"partition": "ea3a0845-694e-4820-9d51-50c7d0a2346",
"timestamp": "2023-05-11T19:32:31.707Z",
"identifiers": [
{
"name": "email",
"value": "no-track-pls@example.com"
}
],
"purposes": [
{
"purpose": "Advertising",
"enabled": true
},
{
"purpose": "Analytics",
"enabled": true
},
{
"purpose": "ProductUpdates",
"enabled": false
}
],
"metadata": [
{
"key": "version",
"value": "1.0.0"
}
]
}
],
"skipWorkflowTriggers": false
}Query for upserting IAB US Privacy string (similar for IAB GPP and IAB TCF):
{
"records": [
{
"identifiers": [
{
"name": "email",
"value": "no-track@example.com"
}
],
"partition": "ea3a0845-694e-4820-9d51-50c7d0a23467",
"timestamp": "2023-05-11T19:32:31.707Z",
"purposes": [
{
"purpose": "Advertising",
"enabled": true
},
{
"purpose": "Analytics",
"enabled": true
}
]
},
{
"identifiers": [
{
"name": "email",
"value": "no-track-pls@example.com"
}
],
"partition": "ea3a0845-694e-4820-9d51-50c7d0a2346",
"timestamp": "2023-05-11T19:32:31.707Z",
"purposes": [
{
"purpose": "Advertising",
"enabled": true
},
{
"purpose": "Analytics",
"enabled": true
}
],
"consentManagement": {
"usp": "1YYN"
}
}
]
}Query for upserting purposes with attribute/custom fields tags:
{
"records": [
{
"identifiers": [
{
"name": "email",
"value": "no-track@example.com"
}
],
"partition": "ea3a0845-694e-4820-9d51-50c7d0a23467",
"timestamp": "2023-05-11T19:32:31.707Z",
"purposes": [
{
"purpose": "Advertising",
"enabled": true,
"workflowSettings": {
"attributes": [
{
"key": "Source",
"values": [
"Mobile iOS App"
]
}
]
}
},
{
"purpose": "Marketing",
"enabled": true,
"workflowSettings": {
"attributes": [
{
"key": "Source",
"values": [
"Mobile iOS App"
]
}
]
}
}
]
}
]
}Query for performing a double opt-in in french with region in France:
{
"records": [
{
"identifiers": [
{
"name": "email",
"value": "no-track@example.com"
}
],
"partition": "ea3a0845-694e-4820-9d51-50c7d0a23467",
"timestamp": "2023-05-11T19:32:31.707Z",
"locale": "fr-FR",
"purposes": [
{
"purpose": "Marketing",
"enabled": true,
"workflowSettings": {
"attributes": [
{
"key": "Double Opt-In",
"values": [
"true"
]
}
],
"region": {
"country": "FR"
}
}
}
]
}
]
}Query for upserting purposes with multiple identifiers and mergeRecordsOnConflict false:
{
"records": [
{
"identifiers": [
{
"name": "email",
"value": "no-track@example.com"
},
{
"name": "phone",
"value": "+11234567890"
}
],
"partition": "ea3a0845-694e-4820-9d51-50c7d0a23467",
"timestamp": "2023-05-11T19:32:31.707Z",
"purposes": [
{
"purpose": "Advertising",
"enabled": true
},
{
"purpose": "Marketing",
"enabled": true
}
],
"options": {
"mergeRecordsOnConflict": false
}
}
]
}200 (OK)
application/jsonReturns whether the operation was successful and the upserted records
Response Body
successbooleanWhether the preferences were updated successfully |
nodesarray<object>User's preference records |
Response Body Example
Success Response:
{
"success": true,
"nodes": [
{
"partition": "ee1a0845-694e-4820-9d51-50c7d0a23467",
"timestamp": "2023-04-11T15:09:28.403Z",
"identifiers": [
{
"name": "email",
"value": "no-track@example.com"
},
{
"name": "phone",
"value": "+11234567890"
}
],
"purposes": [
{
"purpose": "Advertising",
"enabled": true
},
{
"purpose": "Analytics",
"enabled": true
},
{
"purpose": "ProductUpdates",
"enabled": true,
"preferences": [
{
"topic": "Frequency",
"choice": {
"selectValue": "Weekly"
}
},
{
"topic": "Channel",
"choice": {
"selectValues": [
"Email",
"Sms"
]
}
},
{
"topic": "Unsubscribe",
"choice": {
"booleanValue": true
}
}
]
}
],
"consentManagement": {
"usp": null,
"gpp": null,
"tcf": null,
"airgapVersion": null
},
"system": {
"updatedAt": "2023-06-13T08:02:21.793Z",
"decryptionStatus": "DECRYPTED"
},
"metadata": [
{
"key": "version",
"value": "1.0.0"
}
],
"metadataTimestamp": "2023-06-13T08:02:21.793Z"
},
{
"partition": "ee1a0845-694e-4820-9d51-50c7d0a23467",
"timestamp": "2023-05-11T15:09:28.403Z",
"identifiers": [
{
"name": "email",
"value": "no-track-pls@transcend.io"
},
{
"name": "phone",
"value": "+11334567891"
}
],
"purposes": [
{
"purpose": "Advertising",
"enabled": true
},
{
"purpose": "Analytics",
"enabled": true
},
{
"purpose": "ProductUpdates",
"enabled": false
}
],
"consentManagement": {
"gpp": null,
"tcf": null,
"airgapVersion": null,
"usp": "1YYN"
},
"system": {
"updatedAt": "2023-06-13T08:02:21.793Z",
"decryptionStatus": "DECRYPTED"
},
"metadata": [
{
"key": "version",
"value": "1.0.0"
}
],
"metadataTimestamp": "2023-06-13T08:02:21.793Z"
}
]
}400 (Bad Request)
application/jsonBad Request
Response Body
successbooleanWhether the preferences were updated successfully |
nodesarray<object>User's preference records |
errorsarray<string>Examples:
|
failuresarray<object>When partial failures occur, `failures` lists the indices of failed records and their errors. Clients can only retry the failed individual records after addressing the reported errors. |
Response Body Examples
Entire batch failure:
{
"errors": [
"No Preference records were provided. Please provide at least one record to update."
],
"failures": [],
"nodes": []
}Partial failure:
{
"success": false,
"nodes": [
{
"partition": "ee1a0845-694e-4820-9d51-50c7d0a23467",
"timestamp": "2023-04-11T15:09:28.403Z",
"identifiers": [
{
"name": "email",
"value": "foo@acme.io"
}
],
"purposes": [
{
"purpose": "Advertising",
"enabled": true
}
],
"consentManagement": {
"usp": null,
"gpp": null,
"tcf": null,
"airgapVersion": null
},
"system": {
"updatedAt": "2023-06-13T08:02:21.793Z",
"decryptionStatus": "DECRYPTED"
},
"metadata": [
{
"key": "version",
"value": "1.0.0"
}
],
"metadataTimestamp": "2023-06-13T08:02:21.793Z"
},
{
"partition": "ee1a0845-694e-4820-9d51-50c7d0a23467",
"timestamp": "2023-04-11T15:09:28.403Z",
"identifiers": [
{
"name": "email",
"value": "acme@bar.io"
}
],
"purposes": [
{
"purpose": "Advertising",
"enabled": true
}
],
"consentManagement": {
"usp": null,
"gpp": null,
"tcf": null,
"airgapVersion": null
},
"system": {
"updatedAt": "2023-06-13T08:02:21.793Z",
"decryptionStatus": "DECRYPTED"
},
"metadata": [
{
"key": "version",
"value": "1.0.0"
}
],
"metadataTimestamp": "2023-06-13T08:02:21.793Z"
}
],
"failures": [
{
"index": 0,
"error": "Conflicting records found for provided identifiers, but mergeRecordsOnConflict is set to false."
}
],
"errors": []
}401 (Unauthorized)
application/jsonThere was a problem authenticating your request. This may be an issue with the Transcend API key ("authorization" header), or the Sombra API key ("x-sombra-authorization" header used for self-hosted gateways only).
413 (Request Entity Too Large)
application/jsonThe request body is too large. JSON and raw bodies must be less than 50MB. URL encoded bodies must be less than 30MB.
429 (Too Many Requests)
application/jsonYou are sending requests too quickly and have hit our rate limit. If you hit this, you'll need to throttle your request velocity or try again later.
Response Headers
Retry-Afterinteger |
X-RateLimit-Limitinteger |
X-RateLimit-Remaininginteger |
X-RateLimit-Resetinteger |
500 (Internal Server Error)
application/jsonA 5xx error means there is either an issue with your self-hosted gateway, or a Transcend server is having issues. You check our system status at status.transcend.io. Please reach out to Transcend support if you're experiencing this error.
502 (Bad Gateway)
application/jsonAn upstream service on Transcend's side is having issues. You check our system status at status.transcend.io. Please reach out to Transcend support if you're experiencing this error.