This guide walks you through onboarding an end-user using the Custom KYC flow, where you handle identity verification using your own KYC provider (e.g., Sumsub, Persona, Onfido).
Prerequisites
- You have received your business API key
- You have your own KYC verification provider set up
- Your user has completed KYC verification through your provider
Custom KYC Flow Overview
Create end-user record
Create the record with basic information
Generate ToS link
Get a link for user to accept Bridge’s Terms of Service
User accepts ToS
Receive signed_agreement_id after acceptance
Submit KYC data
Send the KYC data you collected from your provider
Poll for approval
Wait for Bridge endorsement approval
Create accounts
User is ready for virtual accounts or liquidation addresses
Step 1: Create End-User Record
Create an end-user record with their basic information:
POST /v0/end-users
{
"externalUserId": "user_123", // Your internal user ID
"email": "[email protected]"
}
// Response
{
"data": {
"id": "770e8400-e29b-41d4-a716-446655440000",
"externalUserId": "user_123",
"email": "[email protected]",
"applicantId": "custom_kyc_business_customer_id_user_123",
"bridgeCustomerId": null, // Will be populated after KYC submission
"createdAt": "2025-10-31T12:00:00Z"
}
}
The externalUserId is YOUR user ID from your database. Use the same ID consistently throughout all API calls for this user.
Step 2: Generate ToS Link
Generate a Terms of Service acceptance link for your user:
POST /v0/end-users/user_123/tos-link
{
"redirectUri": "https://yourapp.com/onboarding/complete" // Optional (only for redirect integration)
}
// Response
{
"data": {
"tosLinkId": "tos_link_12345",
"tosLink": "https://dashboard.bridge.xyz/tos/accept/...",
"tosStatus": "pending"
}
}
Integration Options
You can integrate ToS acceptance in two ways:
iFrame Integration
Redirect Integration
Embed the ToS page directly in your application.
- Display the ToS link in an iframe:
<iframe
id="bridge-tos-iframe"
src="[tosLink from response]"
style="width: 100%; height: 600px; border: none;"
></iframe>
- Listen for the
signed_agreement_id via postMessage:
window.addEventListener('message', (event) => {
// Security: Verify origin
if (event.origin !== 'https://dashboard.bridge.xyz') return;
if (event.data?.signedAgreementId) {
const signedAgreementId = event.data.signedAgreementId;
console.log('Received:', signedAgreementId);
// Example: "69bad66e-e8da-4845-a0be-a8ef3e14f87d"
// Store for next step
sessionStorage.setItem('signedAgreementId', signedAgreementId);
}
});
Benefits: Seamless UX, user stays in your app, no redirect needed. Open ToS page in new window/tab and receive the ID via redirect.
- Direct user to the
tosLink URL
- After acceptance, user is redirected to your
redirectUri:
https://yourapp.com/onboarding/complete?signed_agreement_id=69bad66e-e8da-4845-a0be-a8ef3e14f87d
- Extract the
signed_agreement_id from URL query parameters:
const urlParams = new URLSearchParams(window.location.search);
const signedAgreementId = urlParams.get('signed_agreement_id');
Step 3: Collect KYC Data
While the user is accepting ToS, collect and verify their KYC data using your own verification provider (Sumsub, Persona, Onfido, etc.).
You’ll need:
- Full name (first and last)
- Email address
- Date of birth (YYYY-MM-DD format)
- Residential address
- Government ID document images (drivers license, passport, or national ID)
- SSN (if applicable)
Step 4: Submit Custom KYC Data
After receiving the signed_agreement_id (via either integration method), submit the KYC data:
POST /v0/end-users/user_123/submit-kyc
{
"type": "individual",
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]",
"residential_address": {
"street_line_1": "123 Main St",
"city": "San Francisco",
"subdivision": "CA", // 2-letter state code for US
"postal_code": "94102",
"country": "USA"
},
"birth_date": "1990-01-15",
"signed_agreement_id": "69bad66e-e8da-4845-a0be-a8ef3e14f87d", // From ToS acceptance
"identifying_information": [
{
"type": "ssn",
"issuing_country": "usa",
"number": "123-45-6789"
},
{
"type": "drivers_license",
"issuing_country": "usa",
"number": "D1234567",
"image_front": "data:image/png;base64,...",
"image_back": "data:image/png;base64,..."
}
]
}
// Response
{
"data": {
"id": "770e8400-e29b-41d4-a716-446655440000",
"externalUserId": "user_123",
"email": "[email protected]",
"applicantId": "custom_kyc_business_customer_id_user_123",
"bridgeCustomerId": "cus_1234567890abcdef", // Now populated!
"createdAt": "2025-10-31T12:00:00Z"
}
}
Critical Requirements:
signed_agreement_id is REQUIRED
identifying_information MUST include at least ONE government ID with images
- SSN alone is NOT sufficient
- For US addresses, use 2-letter state code for
subdivision (e.g., “CA”)
- Images must be base64-encoded:
data:image/png;base64,...
Step 5: Poll Customer Status
Poll the customer status endpoint until the endorsement is approved:
GET /v0/end-users/user_123/customer-status
// Response when approved
{
"data": {
"externalUserId": "user_123",
"bridgeCustomerId": "cus_1234567890abcdef",
"kycStatus": "approved",
"status": "active",
"baseEndorsementStatus": "approved", // Must be "approved"!
"baseEndorsementRequirements": {
"complete": ["government_id_verification", "terms_of_service"],
"missing": {},
"pending": [],
"issues": []
}
}
}
Poll every 5 seconds until baseEndorsementStatus is "approved".
Typical approval time in sandbox: 20-30 seconds
Production approval time may vary based on verification complexity
Verification Complete!
Once baseEndorsementStatus is "approved", your user is fully onboarded and ready to use on/off-ramp services.
Next Steps