Identity Verification Webhooks

Webhooks allow your application to receive real-time notifications when events occur in the Trustist platform. Instead of polling for changes, Trustist will POST event data to your specified endpoint.

Overview

When you register a webhook, Trustist will send HTTP POST requests to your URL whenever subscribed events occur. This enables you to:

  • Respond immediately to identity verification session completions
  • Update your database when verification status changes
  • Trigger downstream workflows without polling
  • Provide real-time updates to your users

Available Events

Event Description Trigger
onboard.session.completed Identity verification session has been successfully completed Customer finishes all verification steps
onboard.session.failed Identity verification session has failed verification Customer fails identity or AML checks
๐Ÿ“Œ Note: For payment-related webhooks (payment.completed, payment.failed, etc.), see the Payment Webhooks guide. This page covers webhooks for onboard (identity verification) events only.

Registering a Webhook

Endpoint

POST /v1/onboard/webhooks

Required Permissions: manage_webhooks

Request Body

Field Type Required Description
url string Yes The HTTPS URL to receive webhook POSTs
name string No Friendly name to identify this webhook
events string[] No Event types to subscribe to (defaults to all)

Example Request

{
    "url": "https://yourapp.com/webhooks/trustist",
    "name": "Production Webhook",
    "events": ["onboard.session.completed"]
}

Example Response

{
    "id": "w1234567-89ab-cdef-0123-456789abcdef",
    "tenantId": "t1234567-89ab-cdef-0123-456789abcdef",
    "url": "https://yourapp.com/webhooks/trustist",
    "name": "Production Webhook",
    "events": ["onboard.session.completed"],
    "isActive": true,
    "created": "2025-10-21T10:00:00Z",
    "lastUpdated": "2025-10-21T10:00:00Z"
}

Webhook Payload Structure

All webhook events follow a consistent JSON structure:

{
    "event": "event.name.here",
    "timestamp": "2025-10-21T11:00:00Z",
    "data": {
        // Event-specific data
    }
}

Onboard Session Completed Event

{
    "event": "onboard.session.completed",
    "timestamp": "2025-10-21T11:00:00Z",
    "data": {
        "sessionId": "s1234567-89ab-cdef-0123-456789abcdef",
        "customerId": "c1234567-89ab-cdef-0123-456789abcdef",
        "status": "completed",
        "customer": {
            "id": "c1234567-89ab-cdef-0123-456789abcdef",
            "firstName": "Jane",
            "lastName": "Smith",
            "emailAddress": "[email protected]"
        },
        "progress": {
            "identity": {
                "status": "passed",
                "completedAt": "2025-10-21T10:55:00Z"
            },
            "ais": {
                "status": "passed",
                "completedAt": "2025-10-21T10:58:00Z",
                "accountsVerified": 2
            }
        }
    }
}

Onboard Session Failed Event

{
    "event": "onboard.session.failed",
    "timestamp": "2025-10-21T11:00:00Z",
    "data": {
        "sessionId": "s1234567-89ab-cdef-0123-456789abcdef",
        "customerId": "c1234567-89ab-cdef-0123-456789abcdef",
        "status": "failed",
        "customer": {
            "id": "c1234567-89ab-cdef-0123-456789abcdef",
            "firstName": "John",
            "lastName": "Doe"
        },
        "progress": {
            "identity": {
                "status": "failed",
                "completedAt": "2025-10-21T10:55:00Z",
                "reason": "Document verification failed"
            }
        }
    }
}

Handling Webhooks

Implementation Requirements

Your webhook endpoint must:

  • โœ… Accept HTTP POST requests
  • โœ… Return HTTP 200 status within 10 seconds
  • โœ… Be publicly accessible (not localhost or private network)
  • โœ… Use HTTPS in production (HTTP allowed for testing only)
  • โœ… Process events asynchronously to avoid timeouts
โš ๏ธ Timeout Policy: If your endpoint doesn't respond with 200 OK within 10 seconds, the webhook is marked as failed. After 5 consecutive failures, we'll disable the webhook and notify you.

Example Implementation (Node.js/Express)

const express = require('express');
const app = express();

app.use(express.json());

app.post('/webhooks/trustist', async (req, res) => {
    // Immediately acknowledge receipt
    res.status(200).send('OK');
    
    // Process asynchronously
    processWebhookAsync(req.body).catch(err => {
        console.error('Webhook processing failed:', err);
    });
});

async function processWebhookAsync(payload) {
    const { event, data } = payload;
    
    console.log(`Processing webhook: ${event}`);
    
    switch (event) {
        case 'onboard.session.completed':
            await handleSessionCompleted(data);
            break;
            
        case 'onboard.session.failed':
            await handleSessionFailed(data);
            break;
            
        default:
            console.warn(`Unknown event type: ${event}`);
    }
}

async function handleSessionCompleted(data) {
    const { sessionId, customerId, progress } = data;
    
    // Update your database
    await db.customers.update(customerId, {
        verificationStatus: 'verified',
        verifiedAt: new Date(),
        sessionId: sessionId
    });
    
    // Send notification email
    if (progress.identity.status === 'passed') {
        await sendWelcomeEmail(customerId);
    }
    
    // Trigger next steps in your workflow
    await startAccountProvisioning(customerId);
}

async function handleSessionFailed(data) {
    const { sessionId, customerId, progress } = data;
    
    await db.customers.update(customerId, {
        verificationStatus: 'failed',
        failureReason: progress.identity.reason
    });
    
    await sendVerificationFailedEmail(customerId);
}

app.listen(3000);

Example Implementation (C# ASP.NET Core)

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("webhooks/trustist")]
public class TrustistWebhookController : ControllerBase
{
    private readonly ILogger _logger;
    private readonly IBackgroundTaskQueue _taskQueue;
    
    public TrustistWebhookController(
        ILogger logger,
        IBackgroundTaskQueue taskQueue)
    {
        _logger = logger;
        _taskQueue = taskQueue;
    }
    
    [HttpPost]
    public IActionResult HandleWebhook([FromBody] WebhookPayload payload)
    {
        // Queue for background processing
        _taskQueue.QueueBackgroundWorkItem(async token =>
        {
            await ProcessWebhookAsync(payload, token);
        });
        
        // Immediately return success
        return Ok();
    }
    
    private async Task ProcessWebhookAsync(
        WebhookPayload payload,
        CancellationToken ct)
    {
        _logger.LogInformation("Processing webhook: {Event}", payload.Event);
        
        switch (payload.Event)
        {
            case "onboard.session.completed":
                await HandleSessionCompletedAsync(payload.Data, ct);
                break;
                
            case "onboard.session.failed":
                await HandleSessionFailedAsync(payload.Data, ct);
                break;
                
            default:
                _logger.LogWarning("Unknown event type: {Event}", payload.Event);
                break;
        }
    }
}

Testing Webhooks

Local Development

For local testing, use a tunneling service to expose your localhost:

Using ngrok

# Install ngrok
npm install -g ngrok

# Start your local server (e.g., port 3000)
node server.js

# Create tunnel in another terminal
ngrok http 3000

# Use the ngrok HTTPS URL for your webhook
# Example: https://abc123.ngrok.io/webhooks/trustist

Using Hookdeck (recommended for testing)

Hookdeck provides webhook testing, inspection, and retry capabilities:

  • Inspect webhook payloads in real-time
  • Manually retry failed webhooks
  • Test error scenarios
  • View webhook logs and history

Testing Without a Server

Use webhook.site to get a temporary URL and inspect payloads:

  1. Visit webhook.site
  2. Copy your unique URL
  3. Register it as a webhook in Trustist
  4. Create a test identity verification session
  5. Complete it and view the payload on webhook.site

Managing Webhooks

List All Webhooks

GET /v1/onboard/webhooks

Response:

[
    {
        "id": "w1234567-89ab-cdef-0123-456789abcdef",
        "url": "https://yourapp.com/webhooks/trustist",
        "name": "Production Webhook",
        "events": ["onboard.session.completed"],
        "isActive": true,
        "created": "2025-10-21T10:00:00Z",
        "consecutiveFailures": 0
    }
]

Delete a Webhook

DELETE /v1/onboard/webhooks/{webhookId}

Soft deletes the webhook by setting isActive = false.

Troubleshooting

Common Issues

Webhook Not Receiving Events

Check:

  • Webhook URL is publicly accessible
  • Firewall allows incoming connections
  • SSL certificate is valid (for HTTPS)
  • Webhook is active (isActive: true)
  • Events array includes the event type

Webhook Disabled After Failures

If your webhook has 5+ consecutive failures, it will be automatically disabled. Common causes:

  • Endpoint returns non-200 status code
  • Response timeout (>10 seconds)
  • Network connectivity issues
  • Server errors (500, 502, 503)

Solution: Fix the issue, then delete and re-create the webhook to reactivate it.

Duplicate Events

In rare cases, you may receive the same event multiple times due to retries. Your webhook handler should be idempotent:

async function handleSessionCompleted(data) {
    const { sessionId } = data;
    
    // Check if already processed
    const existing = await db.processedWebhooks.findOne({ sessionId });
    if (existing) {
        console.log('Event already processed, skipping');
        return;
    }
    
    // Process the event
    await updateCustomer(data.customerId);
    
    // Mark as processed
    await db.processedWebhooks.create({ sessionId, processedAt: new Date() });
}

Security Best Practices

  • โœ… Use HTTPS for all webhook URLs in production
  • โœ… Validate the webhook payload structure before processing
  • โœ… Implement rate limiting on your webhook endpoint
  • โœ… Log all webhook receipts for audit purposes
  • โœ… Monitor for suspicious patterns or abuse
  • โŒ Don't use webhooks for time-sensitive operations with strict SLAs
  • โŒ Don't block the HTTP response while processing heavy operations
๐Ÿ’ก Future Enhancement: Webhook signature verification will be added in a future release to cryptographically verify that webhooks originate from Trustist.

Next Steps