Skip to main content

The core trade-off

When integrating with M2M, you control how much user data you provide upfront. This creates a fundamental trade-off:
ApproachIntegration EffortUser FrictionDescription
Full data upfrontHighNoneProvide all user data when creating the link
Webhook fallbackMediumLowProvide partial data, respond to webhooks for the rest
MinimalLowHighOnly provide referenceId, users enter everything

Understanding friction

“Friction” refers to the steps a user must complete before making a transaction:
User opens link and immediately sees:
  • Pre-filled personal information
  • Pre-filled payment method
  • Ready to confirm transaction
No forms to fill, no ID verification prompts.
User opens link and sees:
  • Some pre-filled information
  • May need to confirm or add minor details
  • Quick verification step if needed
Fast completion, minimal input required.
User opens link and must:
  • Enter full legal name (all parts)
  • Enter government ID number
  • Enter date of birth
  • Complete full CIP verification
  • Add payment method
More steps = higher abandonment risk.

Data fields and their impact

Required CIP fields

M2M requires these fields for identity verification (CIP). Each missing field increases friction:
FieldDescriptionImpact if missing
name.firstNameFirst nameUser enters manually
name.secondNameMiddle name / second first nameUser enters manually
name.lastNamePrimary surnameUser enters manually
name.secondLastNameSecondary surname (maternal)User enters manually
idNumberGovernment ID (e.g., CURP)User enters + may need ID verification
idTypeType of ID documentUser selects from list
dobDate of birthUser enters with date picker

Optional but valuable

FieldDescriptionImpact
paymentMethodPayment destination — required when userData is provided (see Payment Methods)User adds payment method if missing
idImageID document photo (base64)May skip photo capture step

Payment methods

The paymentMethod field uses a flexible structure to support different payment types and countries:
For bank transfers, include the country code (ISO 3166-1 alpha-2) and the appropriate account identifier:Mexico (CLABE)
{
  "paymentMethod": {
    "type": "bank_account",
    "bankAccount": {
      "country": "MX",
      "accountNumber": "012345678901234567"
    }
  }
}
Argentina (CBU)
{
  "paymentMethod": {
    "type": "bank_account",
    "bankAccount": {
      "country": "AR",
      "accountNumber": "0110599940000041079153"
    }
  }
}
Colombia
{
  "paymentMethod": {
    "type": "bank_account",
    "bankAccount": {
      "country": "CO",
      "accountNumber": "12345678901234",
      "accountType": "savings",
      "bankCode": "007"
    }
  }
}
FieldRequiredDescription
typeYesMust be bank_account
bankAccount.countryYesISO 3166-1 alpha-2 country code
bankAccount.accountNumberYesAccount identifier (CLABE, CBU, IBAN, etc.)
bankAccount.accountTypeNosavings or checking (required for some countries)
bankAccount.bankCodeNoBank code or routing number (required for some countries)
For card-based payouts, card data must be sent through the VGS Inbound Proxy for PCI compliance. The M2M API only accepts tokenized card numbers.
{
  "paymentMethod": {
    "type": "card",
    "card": {
      "number": "tok_sandbox_4fKq8H2xLmNpRtYw",
      "expiryMonth": "12",
      "expiryYear": "2028",
      "cardholderName": "Juan García",
      "last4": "4242",
      "brand": "visa"
    }
  }
}
Card numbers must be routed through the VGS Inbound Proxy. Never send raw PANs directly to the M2M API. Contact your M2M integration specialist for VGS proxy configuration.
FieldRequiredDescription
typeYesMust be card
card.numberYesVGS-tokenized card number (tok_xxx)
card.expiryMonthYesExpiry month (01-12)
card.expiryYearYesExpiry year (4 digits, e.g., 2028)
card.cardholderNameNoName as it appears on the card
card.last4NoLast 4 digits (VGS can extract this automatically)
card.brandNoCard brand (visa, mastercard, amex, etc.)
For cash pickup at physical locations (coming soon):
{
  "paymentMethod": {
    "type": "cash",
    "cash": {
      "provider": "oxxo"
    }
  }
}

Choose your approach

Option 1: Full data upfront

Best for: Partners with complete KYC data already collected Provide all user data when creating the link:
{
  "referenceId": "user_12345",
  "userData": {
    "name": {
      "firstName": "Juan",
      "secondName": "Carlos",
      "lastName": "Garcia",
      "secondLastName": "Lopez"
    },
    "idNumber": "GALO900515HDFRPN09",
    "idType": "CURP",
    "dob": "1990-05-15",
    "paymentMethod": {
      "type": "bank_account",
      "bankAccount": {
        "country": "MX",
        "accountNumber": "012345678901234567"
      }
    }
  }
}
Result: User opens the link and can immediately complete their transaction. No forms, no verification steps.
Pros:
  • Best user experience
  • Highest conversion rates
  • No webhook infrastructure needed
Cons:
  • Requires all data at link creation time
  • May need to collect data from multiple sources
  • Data must match government records exactly

Best for: Partners who have partial data or need to fetch it asynchronously Provide what you have upfront, respond to webhooks for the rest:
{
  "referenceId": "user_12345",
  "userData": {
    "name": {
      "firstName": "Juan",
      "lastName": "Garcia"
    }
  }
}
When M2M needs more data, you receive a webhook:
{
  "event": "user.data_request",
  "data": {
    "requiredFields": ["name.secondName", "name.secondLastName", "idNumber", "idType", "dob"],
    "replyEndpoint": "https://api.m2m.leapfinancial.com/partner/data-requests/dr_123"
  }
}
You respond with the missing data:
{
  "referenceId": "user_12345",
  "userData": {
    "name": {
      "secondName": "Carlos",
      "secondLastName": "Lopez"
    },
    "idNumber": "GALO900515HDFRPN09",
    "idType": "CURP",
    "dob": "1990-05-15"
  }
}
Result: User sees a partially pre-filled form. If you respond quickly, they may not need to enter anything.
Pros:
  • Flexible - provide what you have
  • Async data fetching supported
  • Good balance of effort vs. UX
  • Graceful degradation if webhook fails
Cons:
  • Requires webhook infrastructure
  • Response time affects UX
  • More complex implementation

Option 3: Minimal integration

Best for: Quick POC or when you have no user data Only provide the user identifier:
{
  "referenceId": "user_12345"
}
Result: User must complete full CIP verification in the widget. Expect lower conversion rates.
Pros:
  • Fastest integration time
  • No data handling required
  • Works for any user
Cons:
  • Highest user friction
  • Lower conversion rates
  • Users may abandon the process

Data source precedence

When the same field is provided from multiple sources, M2M uses this precedence:
PrioritySourceDescription
1 (highest)partner_apiData from link creation API
2partner_webhookData from data request response
3 (lowest)widgetData entered by user
Higher priority data is never overwritten by lower priority data. If you provide firstName during link creation, a webhook response cannot change it.
This means you can safely:
  • Provide partial data upfront
  • Fill in gaps via webhook
  • Let users correct only what’s missing

Recommendations

Don’t wait to collect all data before integrating. Start with the data you have:
  • Name from user profile? Include it.
  • Email but no ID? Include the name, skip the ID.
  • Nothing? Start with minimal and iterate.
Even if you plan to provide full data, implement webhook handling as a safety net:
  • Handles edge cases where data is incomplete
  • Supports users whose data doesn’t match records
  • Future-proofs your integration
Track your users’ journey:
  • How many complete without entering data?
  • Where do users drop off?
  • Which fields cause the most friction?
Use this data to prioritize which fields to provide upfront.
CIP verification compares your data to government records. Mismatches cause friction:
  • Use legal names, not nicknames
  • Format dates correctly (YYYY-MM-DD)
  • Validate ID numbers before submission

Example: Progressive enhancement

Here’s how to evolve your integration over time:

Phase 1: MVP (Day 1)

{
  "referenceId": "user_12345"
}
Focus: Get the integration working. Accept higher friction.

Phase 2: Add name data (Week 2)

{
  "referenceId": "user_12345",
  "userData": {
    "name": {
      "firstName": "Juan",
      "lastName": "Garcia"
    }
  }
}
Focus: Reduce friction with data you already have.

Phase 3: Implement webhooks (Week 4)

Handle user.data_request webhooks to provide:
  • Missing name fields
  • ID number (fetched from your KYC provider)
  • Date of birth
Focus: Minimize user input.

Phase 4: Full data (Week 6+)

{
  "referenceId": "user_12345",
  "userData": {
    "name": { /* all fields */ },
    "idNumber": "...",
    "idType": "CURP",
    "dob": "1990-05-15",
    "paymentMethod": {
      "type": "bank_account",
      "bankAccount": {
        "country": "MX",
        "accountNumber": "012345678901234567"
      }
    }
  }
}
Focus: Zero friction for returning users.

Next steps

User Lifecycle

Learn how M2M manages user state across links.

Data Requests

Implement webhook handling for data requests.