Customer Verification: Integration Guide

This guide walks through the full integration step by step, with example code for each stage. All code examples reference KYC (Know Your Customer) scenarios, but the same pattern applies to KYB (Know Your Business) applications.


Step 1: Create an Application

Before the SDK can be invoked, create an application instance for each customer via the Create Application API. Store the returned id against your customer record - it is used in all subsequent API calls and webhooks.

Note: Create a separate application for each business a customer wishes to onboard, even if ownership is identical across businesses.

POST /applications
{
  "legalEntity": "MFBV"
}

Response (201 Created)

{
  "id": "APP21000MG"
}

Step 2: Submit KYC/KYB Data via API (Optional)

Skip this step if you are using the SDK-only route. Jump straight to Step 5.

If you hold verified customer data already and want to reduce friction in the onboarding journey, you can pre-populate compliance data via the API before invoking the SDK.

Create a Compliance Associate

Submit identity data for each individual (the primary customer or associated individuals for a business application).

POST /applications/{applicationId}/compliance/associates
{
  "types": ["INDIVIDUAL"],
  "firstName": "Clara",
  "middleName": "Optional",
  "lastName": "Burt",
  "dateOfBirth": "1942-01-02",
  "contactDetails": {
    "email": "[email protected]",
    "phone": "07415626822"
  },
  "homeAddress": {
    "addressLine1": "1 House Street",
    "addressLine2": "Optional",
    "country": "GB",
    "postCode": "E147HG",
    "postTown": "Edinburgh"
  }
}

Response (201 Created)

{
  "id": "ASS0000001"
}

Associate types: Use INDIVIDUAL for KYC. For business applications, available types include DIRECTOR, PARTNER, BENE_OWNER, and SOLETRADER.

Submit KYB/KYC Data

Provide expected activity details for the customer's Modulr account.

PUT /applications/APP0000001/compliance/know-your-customer
{
  "expectedMonthlySpend": 10000,
  "expectedMonthlyTransactions": 50
}

Response: 204 No Content

Submit Associate Personal Info

Provide nationality data for the associate.

PUT /applications/{applicationId}/compliance/associates/{associateId}/personal-info
{
  "nationalities": ["GB", "CA"]
}

Response: 204 No Content

Submit Associate Tax Residencies

PUT /applications/{applicationId}/compliance/associates/{associateId}/tax-residencies
{
  "taxResidencies": ["ES", "FR"]
}

Response: 204 No Content


Step 3: Handle APPLICATION_STATUS_CHANGE Webhooks

Once the customer starts entering data, Modulr sends APPLICATION_STATUS_CHANGE webhook events to your registered endpoint. You must process these throughout the entire application lifecycle.

See the full webhook reference: Webhook - Application Status Change

Your webhook handler must be idempotent - the same event may be delivered more than once. Respond with HTTP 200 to acknowledge receipt. Modulr will retry on failure.


Step 4: Initiate Application Verification

If you submitted data via the API in Step 2, call the verify endpoint to trigger Modulr's CDD orchestration. If you used the SDK-only route, the SDK makes this call automatically.

POST /applications/{applicationId}/verify

No request body required.

Response: 200 OK

After this call, monitor APPLICATION_STATUS_CHANGE webhooks. The application will transition to one of:

  • APPROVED - all KYB/KYC checks passed
  • PENDING_STEP_UP - further information required from the customer
  • MANUAL_REVIEW - application queued for human review

Step 5: Create a Short-lived Token

Before initialising the SDK, request a short-lived token and HMAC from the Modulr keys endpoint.

Important: This call must be made server-side. Never expose the token or HMAC in client-side code or logs.

POST /keys/onboarding/{applicationId}

Response (201 Created)

{
  "expires": "2026-04-06 12:31:58",
  "hmac": "sdk::hmac_052c3013012e",
  "token": "token_6e5522ad78ff"
}

The token has a short TTL. Request a fresh token immediately before each SDK initialisation.


Step 6: Initialise the Customer Verification SDK

Use the token, HMAC, and application ID from the previous steps to initialise the SDK.

const sdkInstance = await ModulrCustomerVerificationSdk.init({
  token,
  hmac,
  applicationId: 'APP21000MG',

  onInit: (result) => {
    console.log('SDK initialised:', result.status, result.message);
  },
  onError: (error) => {
    console.error('SDK error:', error);
  }
});

Custom Styling (Optional)

The SDK supports visual customisation to match your product's design system. All styling properties are optional - omit the block entirely to use Modulr defaults.

const sdkInstance = await ModulrCustomerVerificationSdk.init({
  token,
  hmac,
  applicationId: 'APP21000MG',

  customStyle: {
    theme: {
      primaryColor: '#111111',
      backgroundColor: '#FFFFFF',
      textColor: '#111111',
      borderRadius: '4px',
      iconColor: '#111111',
      successColor: '#008756',
      errorColor: '#D91E18'
    },
    componentOverride: {
      PrimaryButton: {
        default: {
          backgroundColor: '#111111',
          textColor: '#FFFFFF',
          borderRadius: '4px',
          border: '#111111',
          boxShadow: '0'
        },
        hover: {
          backgroundColor: '#78808F',
          textColor: '#FFFFFF',
          borderRadius: '4px',
          border: '#78808F',
          boxShadow: '0'
        }
      }
    }
  },

  onInit: (result) => {
    console.log('SDK initialised:', result.status, result.message);
  },
  onError: (error) => {
    console.error('SDK error:', error);
  }
});

Only call open() (Step 7) after onInit fires successfully.


Step 7: Open the Customer Verification SDK

Call open() once the SDK has initialised. The SDK can be displayed as a modal (default) or embedded inline in a container element.

Modal mode (default)

await sdkInstance.open({
  onResult: (data) => console.log('Result:', data),
  onError: (error) => console.error('Error:', error),
  onClose: () => console.log('Closed')
});

Inline / embedded mode

await sdkInstance.open({
  containerId: 'your-container-element-id',
  onResult: (data) => console.log('Result:', data),
  onError: (error) => console.error('Error:', error),
  onClose: () => console.log('Closed')
});

containerId must reference a visible DOM element. Use onClose to clean up your UI when the customer exits the SDK.


Step 8: Close the SDK

The SDK can be closed programmatically at any time.

ModulrCustomerVerificationSdk.close();

The onClose callback registered in open() fires whether the SDK is closed by the user or programmatically.


Step 9: Handle PENDING_STEP_UP

If further information is required after initial submission, Modulr sends an APPLICATION_STATUS_CHANGE webhook with status PENDING_STEP_UP.

When you receive this:

  1. Notify your customer that further information is required.
  2. Re-invoke the SDK (repeat Steps 5-8) using the same applicationId. A fresh short-lived token is required for each invocation.
  3. The SDK will automatically surface the step-up form for the outstanding requirements.

This applies both after automated CDD checks and after a manual review decision - meaning these notifications could come back within a few seconds for automated step-ups, or hours/days after the initial submission depending on the complexity of the manual review.


Step 10: Receive CUSTOMER_CREATED

Once the application reaches APPROVED status, Modulr sends a CUSTOMER_CREATED webhook containing the new customerId.

Store the customerId against your customer record. Use it in subsequent Account Creation API calls.

See the full webhook reference: Webhook - Customer Created


Step 11: Monitor CUSTOMER_STATUS_CHANGE

Once a customer is live on Modulr, monitor the CUSTOMER_STATUS_CHANGE webhook to track ongoing lifecycle events, including BLOCKED status which prevents payment processing.

See the full webhook reference: Webhook - Customer Status Change


Integration Checklist

StepItemRequired?
1Create ApplicationYes
2Submit KYC/KYB Data via APIOptional
3Handle APPLICATION_STATUS_CHANGE webhookYes
4Initiate Application VerificationOnly if using API pre-population
5Create Short-lived TokenYes
6Initialise SDKYes
7Open SDKYes
8Close SDKYes
9Handle PENDING_STEP_UPYes
10Handle CUSTOMER_CREATED webhookYes
11Handle CUSTOMER_STATUS_CHANGE webhookYes