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}/verifyNo 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 passedPENDING_STEP_UP- further information required from the customerMANUAL_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:
- Notify your customer that further information is required.
- Re-invoke the SDK (repeat Steps 5-8) using the same
applicationId. A fresh short-lived token is required for each invocation. - 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
| Step | Item | Required? |
|---|---|---|
| 1 | Create Application | Yes |
| 2 | Submit KYC/KYB Data via API | Optional |
| 3 | Handle APPLICATION_STATUS_CHANGE webhook | Yes |
| 4 | Initiate Application Verification | Only if using API pre-population |
| 5 | Create Short-lived Token | Yes |
| 6 | Initialise SDK | Yes |
| 7 | Open SDK | Yes |
| 8 | Close SDK | Yes |
| 9 | Handle PENDING_STEP_UP | Yes |
| 10 | Handle CUSTOMER_CREATED webhook | Yes |
| 11 | Handle CUSTOMER_STATUS_CHANGE webhook | Yes |
