Identity enrichment webhook

Determine any additional identifiers that are used to key the data subject's identity.

When a request is initially received, we may not have all of the identifiers that we need to look up that user. For example, we may start with an email, and want to find the associated username or user id for that email. In this guide, we outline how Transcend can send a webhook to one of your servers and ask it to look up additional identifier keys.

Setting up your enricher in the Admin Dashboard

Define the identifiers you plan to enrich to

Under Identifiers settings →, make sure each of the identifiers you plan to return is listed. If not, use the + button to define new identifiers.

Note that the identifiers' name that you configure here have to match with the "name" of the identifier used in your payload.

Create a new enricher

Go to the identity enrichers section on the Request Identifiers → tab in Settings. Add a new enricher by clicking the blue + button in the top-right-hand corner of the "Enrichers" section.

Enrichers always take in a single identifier (e.g. an email) and can return many identifiers (e.g. emails, advertising IDs, phone numbers, and custom identifiers such as user IDs).

Enter the URL Transcend should send a POST request to, and which type of identifier it should include in the payload (e.g. an email address). We will send you a webhook whenever we receive a request and containing that type of identifier.

Select the identifiers you plan to return from your enricher & hit save!

Create an API Key

In order to upload the identifier back to Transcend, you will need to create an API key with the Manage Request Identity Verification scope on the Developer Settings → page. Please refer to the creating an API key guide for more information.

Note: if the same server is also used for the Server Webhook Integration, you can use a single API key with scopes for both the data silo and identity enrichment.

Server-side implementation


Check out our code examples

We have examples on GitHub. The javascript example is deployed live at our demo privacy center.

Receiving the webhook

Transcend will send a POST request to the URL that you inputted into the enricher form above. The route should first validate that the webhook is in fact coming from your sombra gateway by validating the incoming x-sombra-token header. Please refer to this guide for information on verifying the webhook signature.

Request headers:

  "x-transcend-nonce": "<A_VALUE_TO_RETURN>",
  "x-sombra-token": "<A_JSON_WEB_TOKEN_TO_VERIFY>",
  "accept": "application/json",
  "content-type": "application/json",
  "via": "HTTPS/1.1 <<yourOrganizationName>> (Sombra)"

Request body:

  "type": "ACCESS", // Could be ERASURE, ...
  "requestIdentifier": {
     "value": "[email protected]"
  "coreIdentifier": {
    "value": "" // The globally unique user ID for the user
  "dataSubject": {
    "type": "customer"
  "isTest": false,
  "extras": {
    "request": {
      "details": "",
      "id": "2cde58cd-5405-434e-8c6a-dd71a726d5b3",
      "link": "",
      "verifiedAt": "2019-04-26T17:55:22.773Z",
      "createdAt": "2019-04-26T17:55:21.723Z",
      "locale": "en",
      "origin": "PRIVACY_CENTER"
    "enricher": {
      "id": "2716d635-f132-45a1-95ae-44a36eae653d"
    "identifier": {
      "id": "63289ec9-113a-4559-a3e5-0b2de30a2743",
      "name": "email",
      "type": "email"
    "requestEnricherId": "6a3cdc8d-581f-43e3-aa7e-a3edc07109d0",
    "organization": {
      "id": "aaba371a-1ca0-4c55-9231-a1d8088a0e7d",
      "name": "<<yourOrganizationName>>",
      "uri": "<<yourOrganizationName>>"

You can grab the identifier to enricher from the webhoook body at requestIdentifier.value. If you route expects multiple types of identifier inputs, you can determine which identifier is being notified by pulling out the field

Additionally, you will want to save the x-transcend-nonce from the headers. You will need it to upload the enriched identifiers later.

Once you have all of the information you need to perform the enrichment, you can enqueue a job to asynchronously process this enrichment request and respond to the webhook with status code 200 to indicate that the webhook was received successfully.

Uploading enriched identifiers

Endpoint reference: Add info to a DSR before processing

  1. Look up the additional identifiers that you wish to return. These identifiers must be predefined on the Admin Dashboard under Identifier settings.
  2. Upload these identifiers to your internal sombra application at POST /v1/enrich-identifiers, with the header x-transcend-nonce from earlier, and a request body containing the enriched identifiers like so:
POST <<yourOrganizationSombraURL>>/v1/enrich-identifiers

JSON Body Fields






Mapping from identifier name to a list of enricher identifiers of that type.

  enrichedIdentifiers: {
    googleAnalyticsInternalId: [{
      name: 'googleAnalyticsInternalId'
    gpadvid: [{
      value: 'b20f48d8-9f50-447a-a446-1d398a9f9b1b',
      name: 'gpadvid'

Request Headers





x-sombra-authorization (on premise sombra only)



The nonce from the original webhook. This is in the webhook request header x-transcend-nonce



Full example

You can check out the code example below of this process:

// external modules
import * as jwt from 'jsonwebtoken';
import rp from 'request-promise';

const MOCK_DB = {
  1234: {
    phone: { countryCode: 'US', number: '+18001234567' }, // required format
    username: 'mfred',
    email: '[email protected]'
  5678: {
    phone: { countryCode: 'US', number: '+18002143567' },
    username: 'fredm',
    email: '[email protected]'

 * Async process to enrich identities + upload to Transcend through Sombra
async function scheduleEnricher(identifier, nonce) {
    // Look up the additional identifiers that you wish to return
    const extraIdentifiers = MOCK_DB[identifier];
      url: `${SOMBRA_URL}/v1/enrich-identifiers`,
      method: 'POST',
      headers: {
        authorization: `Bearer ${transcendApiKey}`,
        'x-transcend-nonce': nonce,
        'x-sombra-authorization': `Bearer ${sombraApiKey}`,
      json: true,
      body: {
        enrichedIdentifiers: [extraIdentifiers]

 * Enricher resolver
async function enricherController(req, res, next) {
  try {
    // 1. Authenticate the incoming webhook and get the verified JWT
    let signedBody;
    try {
      // Sample function:
      signedBody = await verifyAndExtractWebhook(req.headers['x-sombra-token']);
    } catch (error) {
      // If the webhook doesn't pass verification, reject it.
      return res.status(401).send('You are not Transcend!');
    const nonce = req.headers['x-transcend-nonce']
    // 2. Grab the identifier from the verified JWT
    //    This body looks different depending on what type of identifier it is.
    const requestIdentifier = signedBody.value;

    // 3. Schedule the enricher
    scheduleEnricher(requestIdentifier, nonce)
    // 4. Respond with a 200 to acknowledge that you've received the request
  } catch (err) {


Security Tip: Always verify the x-sombra-token JWT header

When you expose your route to the internet, you must be certain that only Sombra can send authenticated requests.

Automatically rejecting or pausing certain DSRs

Endpoint reference: Add info to a DSR before processing

Some companies need to cancel (or place on hold) a request—the data subject may be on some special list (anti-fraud, legal hold, do not delete). Using an enricher, you can automatically cancel the request before it begins processing. Instead of returning a list of identifiers, you can instead specify the request status to transition the request, as well as an optional email template to use if there is a specific reason for the request being canceled.

POST <<yourOrganizationSombraURL>>/v1/enrich-identifiers

Value of status

Use when...


Transcend should cancel the request altogether (i.e. the user failed the anti-fraud check)


Transcend should place a hold on the request for human review (i.e. the user is flagged as risky)

To respond with a status, simple response with status: <STATUS> in the request body with status code 200.

  "status": "CANCELED"  // or "ON_HOLD"

You can also specify the email template to use when canceling the request

  "status": "CANCELED",
  "templateId": "93d31e79-04c4-493d-8f16-38a9d9da5053"

To find the ID of the template you would like to specify, navigate to the template settings page, click the pencil icon for the template you wish to use, and copy the ID.

Note: the default template will be used if none is provided.