Query the Record of Consent (ROC) timeline for a single user. Every consent update that Transcend archives for that user is returned as one record, oldest first, so you can reconstruct what the user consented to at any point in time.

Each record reports the cumulative purpose and preference state at that timepoint, plus a diff against the previous record. Pass includeRawRequest to also receive the original archived payload for each record.

Rate Limits

  • 100 requests per organization per minute (default).
  • This limit can be increased upon request.

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.

Timeline ordering and diffs

  • Records are returned most recent first, in chronological order.
  • preferencesAtCurrentTime is the full cumulative state of every purpose the user has ever set at the time that record was received.
  • changeFromPrevState splits the change introduced by the record into added, removed and updated purposes. It is absent on the first record in the timeline, because there is no earlier record to compare against.
  • Diffs are computed at the purpose and preference level only. IAB strings (tcf, gpp, usp) are not diffed — set includeRawRequest to true and compare consecutive raw payloads if you need to audit those.

Limits

  • This endpoint is not cursor-paginated. Omit limit to receive the entire timeline in one response.
  • limit must be between 1 and 200. When provided, the most recent limit records are returned.
  • containsInitialRecord is always computed against the full timeline, even when limit truncates the returned records. It tells you whether the archive still holds the very first consent record for this user, which is what determines whether the timeline contains the true starting point or a partial view.

Identifiers

  • Provide a single plaintext identifier. The gateway validates, normalizes and encrypts it before the lookup, so plaintext identifiers never reach Transcend storage.
  • identifier.name defaults to the primary identifier configured for the partition, which is email unless you have configured otherwise.
  • The lookup expands to every identifier linked to the same user, so querying by phone number returns the same timeline as querying by that user’s email.
  • Identifiers inside rawRequest are decrypted by your Sombra before being returned on this endpoint.

Raw archived records

  • rawRequest is present only when includeRawRequest is true.
  • Unlike preferencesAtCurrentTime, a raw record reflects exactly what was submitted: consent may be null to indicate the purpose was cleared, and choice may be null to indicate a preference was cleared.

Empty results

  • A user with no archived consent history returns { "records": [], "containsInitialRecord": false } rather than a 404.

POST

/v1/preferences/{partition}/consent-records

In 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:

View Managed Consent Database Admin API

authorizationstring
An API key generated from the Transcend dashboard: https://app.transcend.io/infrastructure/api-keys.
x-sombra-authorizationstring
The 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-typestring
Specify content-type: application/json for a JSON response from the Transcend API.
partitionstring
The ID of the partition in the Preference Store.

application/json

identifierobject(required)
The user whose Record of Consent timeline should be returned.
limitnumbermin:1max:200
Maximum number of records to return, counting from the most recent. Omit to return the full timeline.
includeRawRequestbooleandefault:false
Whether to include the raw archived payload for each record in the `rawRequest` field.

Request Body Examples

Query a user's full consent timeline:

{
  "identifier": {
    "name": "email",
    "value": "no-track@example.com"
  }
}

Query by a non-default identifier:

{
  "identifier": {
    "name": "phone",
    "value": "+11234567890"
  }
}

Query using the default identifier name for the partition:

{
  "identifier": {
    "value": "no-track@example.com"
  }
}

Return only the ten most recent records:

{
  "identifier": {
    "name": "email",
    "value": "no-track@example.com"
  },
  "limit": 10
}

Include the raw archived payloads:

{
  "identifier": {
    "name": "email",
    "value": "no-track@example.com"
  },
  "includeRawRequest": true
}

200 (OK)

application/json

Returns the user's Record of Consent timeline

Response Body

recordsarray<object>(required)
The Record of Consent timeline for the user, ordered oldest first. Empty when no consent history is archived for this user.
containsInitialRecordboolean(required)
Whether the archive still holds the very first consent record for this user. When `false`, the timeline begins partway through the history and `records[0]` is not a true starting point. Always computed against the full timeline, even when `limit` truncates the response.

Response Body Examples

Response for a user with two consent records:

{
  "records": [
    {
      "preferencesAtCurrentTime": [
        {
          "purpose": "Marketing",
          "consent": true,
          "timestamp": "2024-10-07T20:44:35.000Z",
          "preferences": []
        }
      ]
    },
    {
      "preferencesAtCurrentTime": [
        {
          "purpose": "Marketing",
          "consent": true,
          "timestamp": "2024-10-07T20:44:35.000Z",
          "preferences": [
            {
              "topic": "Frequency",
              "choice": {
                "selectValue": "Weekly"
              }
            }
          ]
        },
        {
          "purpose": "Analytics",
          "consent": true,
          "timestamp": "2024-10-08T20:44:35.000Z",
          "preferences": []
        }
      ],
      "changeFromPrevState": {
        "added": [
          {
            "purpose": "Analytics",
            "consent": true,
            "timestamp": "2024-10-08T20:44:35.000Z",
            "preferences": []
          }
        ],
        "removed": [],
        "updated": [
          {
            "purpose": "Marketing",
            "consent": true,
            "timestamp": "2024-10-07T20:44:35.000Z",
            "preferences": [
              {
                "topic": "Frequency",
                "choice": {
                  "selectValue": "Weekly"
                }
              }
            ]
          }
        ]
      }
    }
  ],
  "containsInitialRecord": true
}

Response including the raw archived payloads:

{
  "records": [
    {
      "preferencesAtCurrentTime": [
        {
          "purpose": "Marketing",
          "consent": true,
          "timestamp": "2024-10-07T20:44:35.000Z",
          "preferences": []
        }
      ],
      "rawRequest": {
        "timestamp": "2024-10-07T20:44:35.000Z",
        "confirmed": true,
        "partition": "ee1a0845-694e-4820-9d51-50c7d0a23467",
        "metadata": null,
        "identifiers": [
          {
            "name": "email",
            "value": "no-track@example.com"
          }
        ],
        "purposes": [
          {
            "purpose": "Marketing",
            "consent": true,
            "timestamp": "2024-10-07T20:44:35.000Z",
            "preferences": []
          }
        ]
      }
    },
    {
      "preferencesAtCurrentTime": [],
      "changeFromPrevState": {
        "added": [],
        "removed": [
          {
            "purpose": "Marketing",
            "consent": true,
            "timestamp": "2024-10-07T20:44:35.000Z",
            "preferences": []
          }
        ],
        "updated": []
      },
      "rawRequest": {
        "timestamp": "2024-11-02T09:12:04.000Z",
        "confirmed": true,
        "partition": "ee1a0845-694e-4820-9d51-50c7d0a23467",
        "metadata": "{\"version\":\"1.0.0\"}",
        "identifiers": [
          {
            "name": "email",
            "value": "no-track@example.com"
          }
        ],
        "purposes": [
          {
            "purpose": "Marketing",
            "consent": null,
            "timestamp": "2024-11-02T09:12:04.000Z"
          }
        ]
      }
    }
  ],
  "containsInitialRecord": true
}

Response for a truncated timeline:

{
  "records": [
    {
      "preferencesAtCurrentTime": [
        {
          "purpose": "Marketing",
          "consent": true,
          "timestamp": "2024-10-07T20:44:35.000Z",
          "preferences": []
        }
      ]
    }
  ],
  "containsInitialRecord": true
}

Response for a user with no Record of Consent history:

{
  "records": [],
  "containsInitialRecord": false
}

400 (Bad Request)

application/json

Bad Request

Response Body

errorsarray<string>
Examples:
  • Client error: Limit must be between 1 and 200
  • Client error: Invalid partition provided.
  • Client error: Invalid ROC user query request
  • Client error: Invalid ROC user query limit
  • Client error: ROC user query limit cannot exceed 200
  • Client error: Payload does not conform to the expected schema
  • Client error: Failed to encrypt the provided identifier.
  • Missing consent identifier encryption key. Please ensure that your Sombra is configured correctly with a `CONSENT_IDENTIFIER_ENCRYPTION_KEY`.
  • Identifier [identifier_name] did not pass validation: [reason]
  • An unknown error occurred while validating identifiers.

401 (Unauthorized)

application/json

There 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/json

The 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/json

You 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/json

A 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/json

An 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.