Tenant Webhooks

Receive real-time notifications for tenant-scoped events. Trustist sends HTTP POST payloads to your endpoint so you can react without polling.

Overview

Tenant webhooks currently help you:

  • React when identity verification sessions complete
  • Update your internal workflow state from webhook events
  • Trigger follow-up checks and customer journeys asynchronously

Available Events

Event Description Trigger
onboard.session.completed Onboard session has completed Customer finishes all required onboarding steps
Note: Payment and standing order webhooks are documented separately in Payment Webhooks.

Registering a Webhook

Endpoint

POST /v1/webhooks

Required Permission: manage_webhooks

Backward compatibility: /v1/tenant/webhooks and /v1/onboard/webhooks are also accepted.

Request Body

Field Type Required Description
url string Yes Absolute URL to receive webhook POSTs (HTTPS recommended)
events string[] No Subscribed event names. Defaults to ["onboard.session.completed"] when omitted; empty arrays are rejected

Example Request

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

Example Response

{
    "id": "w1X2y3Z4",
    "url": "https://yourapp.com/webhooks/trustist",
    "name": "Production Tenant Webhook",
    "events": ["onboard.session.completed"],
    "active": true,
    "created": "2025-10-21T10:00:00Z",
    "updated": "2025-10-21T10:00:00Z",
    "lastDelivered": null,
    "deliveryAttempts": 0
}

Webhook Payload Structure

Current payload shape for onboard.session.completed (note the PascalCase property names):

{
    "Event": "onboard.session.completed",
    "Timestamp": "2025-10-21T11:00:00Z",
    "Session": {
        "Id": "12345678-89ab-cdef-0123-456789abcdef",
        "Status": "Complete",
        "Progress": {
            "Identity": {
                "Completed": true,
                "Confirmed": true,
                "CompletedAt": "2025-10-21T10:55:00Z"
            },
            "Ais": {
                "Completed": false,
                "Confirmed": null,
                "CompletedAt": null
            }
        },
        "Created": "2025-10-21T10:30:00Z",
        "Updated": "2025-10-21T10:59:00Z"
    }
}

Handling Webhooks

Implementation Requirements

  • Accept HTTP POST requests
  • Return a 2xx HTTP status code quickly
  • Keep endpoint publicly reachable
  • Process webhook work asynchronously
  • Implement idempotency for duplicate deliveries
Delivery behavior: tenant webhook delivery is currently attempted once per event per active endpoint. Failed attempts increment deliveryAttempts; there is no automatic disable threshold in this service.

Example Implementation (Node.js/Express)

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

app.use(express.json());

app.post('/webhooks/trustist', async (req, res) => {
    res.status(200).send('OK');

    processWebhookAsync(req.body).catch(err => {
        console.error('Webhook processing failed:', err);
    });
});

async function processWebhookAsync(payload) {
    const { Event, Session } = payload;

    if (Event !== 'onboard.session.completed') {
        console.warn(`Unknown event type: ${Event}`);
        return;
    }

    await handleSessionCompleted(Session);
}

async function handleSessionCompleted(session) {
    const { Id, Status, Progress } = session;

    await db.onboardSessions.upsert({
        sessionId: Id,
        status: Status,
        identityCompleted: Progress?.Identity?.Completed ?? false,
        updatedAt: new Date()
    });

    // Follow-up pattern: fetch detailed checks after completion.
    await queueFetchResults(Id);
}

app.listen(3000);

Example Implementation (C# ASP.NET Core)

using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("webhooks/trustist")]
public class TrustistWebhookController : ControllerBase
{
    [HttpPost]
    public IActionResult HandleWebhook([FromBody] WebhookPayload payload)
    {
        _ = ProcessWebhookAsync(payload);
        return Ok();
    }

    private async Task ProcessWebhookAsync(WebhookPayload payload)
    {
        if (payload.Event != "onboard.session.completed")
        {
            return;
        }

        await _sessionStore.UpsertAsync(new SessionRecord
        {
            SessionId = payload.Session.Id,
            Status = payload.Session.Status,
            IdentityCompleted = payload.Session.Progress?.Identity?.Completed ?? false,
            Updated = DateTime.UtcNow
        });

        await _resultsQueue.EnqueueAsync(payload.Session.Id);
    }
}

Testing Webhooks

Local Development with 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

# Register the ngrok HTTPS URL as your webhook endpoint

Inspect Payloads

  1. Use webhook.site to generate a temporary endpoint
  2. Register that URL via POST /v1/webhooks
  3. Complete a session
  4. Inspect the payload and status code response

Managing Webhooks

List Webhooks

GET /v1/webhooks

Delete a Webhook

DELETE /v1/webhooks/{webhookId}

Deletion is a soft delete (active = false).

Troubleshooting

Webhook Not Receiving Events

  • Check endpoint URL is public and reachable
  • Check endpoint returns 2xx status
  • Check webhook is active
  • Check subscription includes onboard.session.completed

Delivery Failures

  • Inspect deliveryAttempts and lastDelivery from list response
  • Review endpoint logs for request/response details
  • Fix endpoint behavior and keep webhook active or recreate if needed

Duplicate Events

Design handlers to be idempotent and deduplicate by event/session identity.

async function handleSessionCompleted(session) {
    const existing = await db.processedWebhooks.findOne({ sessionId: session.Id });
    if (existing) return;

    await processSession(session);
    await db.processedWebhooks.create({ sessionId: session.Id, processedAt: new Date() });
}

Security Best Practices

  • Use HTTPS endpoints in production
  • Validate payload shape before processing
  • Acknowledge quickly and queue heavy work
  • Log receipts and failures for auditability
Future enhancement: webhook signature verification is planned to support payload authenticity checks.

Next Steps