User Onboarding & KYB
Cleavr Connect provides a streamlined onboarding flow that handles KYB (Know Your Business) verification, payment setup, and compliance requirements—all in one seamless experience.
Platform Accounts vs User Accounts: Platform accounts are separate from direct Cleavr accounts. Users creating accounts through your platform will have dedicated platform-linked accounts.
Onboarding Flow Overview
Three-phase onboarding journey from setup to completion.
Detailed Steps: Setup (create user, prefill data) → Verification (hosted onboarding, KYB, terms) → Complete (platform callback, user ready to send receivables)
Implementation
Step 1: Create User Account
Create a user account with prefilled data from your platform:
const user = await cleavr.users.create({ // Required fields email: 'user@company.com',
// Company information (prefillable) company: { name: 'ACME Corporation', siret: '12345678900001', // French company ID vat_number: 'FR12345678901', address: { line1: '123 Rue de la Paix', line2: 'Floor 3', city: 'Paris', postal_code: '75001', country: 'FR' }, website: 'https://acme-corp.com' },
// User information (prefillable) contact: { first_name: 'Jean', last_name: 'Dupont', phone: '+33612345678', job_title: 'CEO' },
// Platform configuration platform: { callback_url: 'https://yourapp.com/onboarding/complete', metadata: { platform_user_id: 'usr_123456', account_type: 'premium' } }});Response:
{ "id": "usr_clv_a1b2c3d4e5f6", "email": "user@company.com", "status": "pending_onboarding", "onboarding_url": "https://onboarding.api.cleavr.fr/start?token=xxx", "created_at": "2025-08-28T10:00:00Z"}Step 2: Direct to Hosted Onboarding
Redirect the user to complete onboarding:
// Option 1: Full page redirectwindow.location.href = user.onboarding_url;
// Option 2: Modal/iframe (if enabled for your platform)const modal = new CleavrOnboardingModal({ url: user.onboarding_url, onComplete: (result) => { console.log('Onboarding completed:', result); }, onCancel: () => { console.log('User cancelled onboarding'); }});modal.open();Step 3: Handle Callback
After onboarding completion, we redirect to your callback URL:
https://yourapp.com/onboarding/complete? user_id=usr_clv_a1b2c3d4e5f6& status=completed& signature=xxxVerify the callback signature:
app.get('/onboarding/complete', async (req, res) => { const { user_id, status, signature } = req.query;
// Verify signature const expectedSignature = crypto .createHmac('sha256', WEBHOOK_SECRET) .update(`${user_id}:${status}`) .digest('hex');
if (signature !== expectedSignature) { return res.status(400).send('Invalid signature'); }
// Check onboarding status if (status === 'completed') { // User is ready to send receivables await markUserAsOnboarded(user_id); res.redirect('/dashboard?onboarding=success'); } else { // Handle incomplete onboarding res.redirect('/dashboard?onboarding=incomplete'); }});Checking Onboarding Status
Get User Requirements
Check what's missing for a user to be fully onboarded:
const requirements = await cleavr.users.getRequirements(userId);Response:
{ "user_id": "usr_clv_a1b2c3d4e5f6", "status": "pending_verification", "requirements": { "currently_due": [ "identity_document", "proof_of_address" ], "eventually_due": [ "business_registration" ], "past_due": [], "errors": [] }, "capabilities": { "send_receivables": false, "receive_payments": false }, "verification": { "identity": "pending", "business": "verified", "bank_account": "verified" }}Status Webhooks
Subscribe to onboarding status changes:
{ "event": "user.onboarding.updated", "data": { "user_id": "usr_clv_a1b2c3d4e5f6", "status": "completed", "capabilities": { "send_receivables": true, "receive_payments": true } }}Prefilling Strategies
Maximum Prefill
Prefill everything you have to minimize user friction:
const userData = { email: platformUser.email, company: { name: platformUser.company_name, siret: await fetchFromAPI('sirene', platformUser.company_name), vat_number: platformUser.vat_id, address: { ...platformUser.billing_address }, website: platformUser.website, phone: platformUser.company_phone }, contact: { first_name: platformUser.first_name, last_name: platformUser.last_name, phone: platformUser.mobile_phone, job_title: platformUser.position, civility: platformUser.title // 'M', 'Mme', 'Mx' }, legal_representative: { first_name: platformUser.legal_rep_first_name, last_name: platformUser.legal_rep_last_name, date_of_birth: platformUser.legal_rep_dob, nationality: platformUser.legal_rep_nationality }};Terms of Service
Automatic Acceptance
Terms are accepted as part of the onboarding flow:
// Terms acceptance is tracked automatically{ terms_accepted: { version: "2025.8", accepted_at: "2025-08-28T10:30:00Z", ip_address: "192.168.1.1", user_agent: "Mozilla/5.0..." }}Troubleshooting
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| Onboarding URL expired | URLs expire after 7 days | Generate new URL with getOnboardingUrl() |
| KYB verification stuck | Missing documents | Check getRequirements() for missing items |
| Callback not received | Network issue | Implement webhook backup |
| Duplicate user | Email already exists | Use unique email per platform account |
Next Steps
Once users are onboarded:
