Set up webhooks

This guide explains how to create, verify, enable and process webhook subscriptions.

Step 1: Create your endpoint

Create the endpoint that will receive the event notifications that you subscribed to.

Your endpoint URL must be able to handle both POST and GET requests. Event notifications are sent to the URL via POST requests in the format described in Step 6. A challenge-response flow to verify that you own the URL is initiated with a GET request, as described in Step 3. Your endpoint must respond to the challenge with an HTTP success status code (2xx) and pass the request's X-Verification-Key header value in the response's JSON payload:

Copy
Copied
{
    "key": "<key-value>"
}

Where <key-value> is the value received in the X-Verification-Key header.

Step 2: Create webhook

You can create a webhook via the Admin Portal or the Webhooks APIs.

In this example, the API is used to create a webhook:

Copy
Copied
curl -i -X POST \
  'https://api.transmitsecurity.io/cis/v1/webhooks' \
  -H 'Authorization: Bearer 91827321837bdfjf' \
  -H 'Content-Type: application/json' \
  -d '{
        "uri": "https://acme.com/external/transmit-user-events",
        "api_key": "34dc49a6-0fae-4ce6-97c4-ca9ad4123b0d",
        "subscribed_events": [
            "User created",
            "User deleted"
        ],
        "name": "User info",
        "description": "Send notifications whenever a user is created or deleted"
    }'
Note

Make sure you have a valid client access token to authorize the request. Since this is a tenant-level operation, the token will need tenant-level authorization (based on a Management Application). If you don't already have a token, you'll need to get one. Learn more

The above request creates a webhook named User info, subscribes to the User created and User deleted events, and defines the URL to which notifications are sent as https://acme.com/external/transmit-user-events. It also sets a value for the api_key, which should be used to validate your the event notifications were sent by Mosaic.

The response to this request includes an autogenerated webhook_id, which is used to identify the webhook in requests.

Step 3: Verify webhook

Before Mosaic sends notifications to your webhook, its URL must be verified. This is done with a challenge-response flow, where Mosaic sends a unique key to the webhook's URL in a GET request (in the X-Verification-Key header) and expects to receive the header value in the response payload. Once the response is successfully received, the webhook is considered verified.

Note

Each webhooks only needs to be verified once.

To perform a verification flow:

  1. Send a POST request to the Webhook Verification API , where <webhook-id> is the ID of the webhook you want to verify (the ID generated in step 2 ):
    Copy
    Copied
    curl -i -X POST \
    https://api.transmitsecurity.io/cis/v1/webhooks/verify/<webhook-id> \
    -H 'Authorization: Bearer 91827321837bdfjf' \

    Upon receiving this request, Mosaic sends a challenge to your webhook endpoint using a GET request like this:

    Copy
    Copied
    Accept: application/json, text/plain, */* \
    content-length: 0 \
    Host: acme.com \
    user-agent: PostmanRuntime/7.29.2 \
    Via: 1.1 google \
    X-API-Key: 34dc49a6-0fae-4ce6-97c4-ca9ad4123b0d \
    X-Scheme: https \
    X-Verification-Key: GoO8Z3hJxx826qTmvwepy \
  2. Upon receiving this challenge, your endpoint must:
    • Validate the X-API-Key header value is identical to the api_key value used to create the webhook in step 2 .
    • Retrieve the X-Verification-Key header value and return it as part of the response's JSON payload.
    • Respond with a success code ( 2xx ).

    Here is a sample code snippet:

    Copy
    Copied
    // Verifies the webhook
    webhook.define('/transmit-user-events','GET', function(req, res) {
    
        // Retrieve the header value
        var key = req.get("X-Verification-Key");
        var mosaic_webhook_token = "34dc49a6-0fae-4ce6-97c4-ca9ad4123b0d";
    
        // Make sure the request token is valid
        if (req.get("X-API-Key") != mosaic_webhook_token) {
            return res.send(400, 'Invalid request');
        }
    
        // Set the response type
        res.type('application/json');
    
        // Set the status code of the response.
        res.status(200);
    
        // Send the key value in the body
        res.json({
            "key": key
        });

    Once the challenge is completed, Mosaic returns a 201 status code to your initial verification call with this JSON body:

    Copy
    Copied
    {
        "verified": true
    }

Step 4: Enable webhook

Notifications are only sent to a webhook after you enable it, either from the Admin Portal and via the API.

To enable a webhook via the API, send a PATCH request to the webhooks endpoint, where <webhook-id> is the ID of the webhook you want to enable (the ID generated in step 2).

Copy
Copied
curl -i -X PATCH \
  'https://api.transmitsecurity.io/cis/v1/webhooks/<webhook-id>' \
  -H 'Authorization: Bearer 91827321837bdfjf' \
  -H 'Content-Type: application/json' \
  -d '{
        "enabled": true
    }'

Step 5: Validate notification

Whenever you receive an event notification, your endpoint needs to validate the request to make sure it was indeed sent by Mosaic. This is done by checking that the X-API-Key header value is identical to the api_key value used to create the webhook in step 2. Once validated, return a 200 response.

Note

If an HTTP success status code (2xx) response is not received within 3 seconds, Mosaic will attempt to send the notification again (up to two more times).

Step 6: Parse event data

All Mosaic webhooks use the same schema, which can be parsed as needed.

Webhooks contain a JSON body, with the following structure:

Field Type Description
event_id String The ID of the event.
tenant_id String The ID of the tenant in which the event was performed.
app_id String The ID of the app for which the event was performed.
event_type String The event type, as described below.
timestamp String The time the event occurred, using the ISO 8601 format.
payload Object Object containing user information

The event_type may correspond to one of these values:

Event Description
User created User was created by an admin, or implicitly upon authenticating
User updated User's profile was updated
User deleted User was deleted
User added to app User was associated with an app
User removed from app User was removed from an app
User logged in User successful authenticates
User logged out User logs out of the session (via Logout API)
User suspended User was suspended
User unsuspended User status was changed from suspended to active
User password lock A lockout applies on user password authentication
Orchestrated user login User was logged in within an orchestrated journey
Failed OTP attempt Last email or phone verification with OTP failed

The payload object contains these fields:

Field Type Description
user_id String The ID of the user for which the action was performed.
created_at Number The time the user was created, as a unix-epoch encoded timestamp in milliseconds.
updated_at Number The last time the user was updated, as a unix-epoch encoded timestamp in milliseconds.
status String The user's status, which can be Active, Pending, or Suspended.
email Object Object containing the user's primary email address (value, string) and verification state (email_verified, boolean).
phone_number Object Object containing the user's primary mobile (value, string) and verification state (phone_number_verified, boolean).

Here is an example payload:

Copy
Copied
{
    "event_id": "tdl4yENhzpZ-GvbAx5cGQ",
    "tenant_id": "wdrCjEPYOLQNQrqmXLnDt",
    "app_id": "DSaI3VGBp4nepRE656XPB",
    "event_type": "User created",
    "timestamp": "2022-07-21T18:15:34.134Z",
    "payload": {
        "user_id": "ue3N8fKgygwfkxC7GXhFV",
        "created_at": 1658427334127,
        "updated_at": 1658427334127,
        "status": "Pending",
        "email": {
            "value": "user@acme.com",
            "email_verified": true
        },
        "phone_number": {
            "value": "+19999999999",
            "phone_number_verified": true
        }
    }
}