Option 3: Headless KYC
Note: This feature is only available to merchants configured by the Breeze team. Please reach out to the Breeze team to find out more.
Overview
This guide explains how to submit KYC data for your customers directly to Breeze via API, without any Breeze-hosted UI. This allows you to own the entire customer-facing KYC experience, while Breeze handles identity verification and compliance checks under the hood.
By submitting KYC data via the Headless KYC API, Breeze can:
- Run identity verification and PEP & sanctions screening in the background, without requiring any input from your customer on a Breeze-hosted page.
- Return a KYC status (approved, pending, or rejected) that you can use to gate payout eligibility within your own UI.
- Ensure a seamless payout experience for platforms that already collect and verify customer identity data internally.
This is the recommended integration path for merchants who run their own KYC process and want to deliver a fully embedded, low-friction payout experience to their users.
Before You Start
A few things to note before you begin integration:
- SSN — Last 4 Digits Are Sufficient
- Full SSN is not required. The last 4 digits of the user's social security number are fully acceptable for Breeze's identity verification process. This is not a blocker.
- Consent — T&C Acceptance
A consent screen must be shown to the customer before any KYC data is submitted, capturing explicit agreement to:
- Your own Terms & Conditions
- Breeze's Terms & Conditions and Privacy Policy
- Persona's Privacy Policy — Breeze's identity verification partner, covering biometric data collection and processing
Recommended consent language:
"By clicking 'Continue,' you consent to Breeze's Terms and Privacy Policy. You also consent to Persona, Breeze's identity verification partner, collecting and processing your biometric information in accordance with its Privacy Policy."
The consent confirmation must be passed as part of the
POST /v1/headless_kycrequest via theconsentobject, which includestermsAcceptedAt,ipAddress, and optionallyuserAgent. Exact wording can be aligned with both legal teams before go-live.
How It Works (Conceptual Overview)
sequenceDiagram
participant Merchant
participant Customer
participant Breeze
participant Persona
Note over Customer, Merchant: Step 1 – Customer submits KYC + consent on your UI
Customer->>Merchant: Fills in KYC data and accepts T&Cs
Note over Merchant: Step 2 – Your internal KYC review
Merchant->>Merchant: Run internal compliance review
Note over Merchant, Breeze: Step 3 – Submit KYC to Breeze
Merchant->>Breeze: POST /v1/headless_kyc (KYC data + tncAcceptedAt)
Breeze->>Persona: Submit KYC data for verification
Persona-->>Breeze: Verification result
Breeze-->>Merchant: Return KYC status (approved / pending / rejected)
Note over Merchant, Customer: Step 4 – Notify customer
Merchant->>Customer: Notify when payout capability is available
Integration Steps
Step 1 — Collect KYC Data & Consent (Your UI)
Display the consent screen to your user and collect the following data. All fields marked ✅ are required.
| Field | Type | Required | Notes |
|---|---|---|---|
customerReferenceId | string | ✅ | Your unique ID for this user. Max 255 chars |
tier | string | ✅ | Must be TIER_2 |
email | string | ✅ | Max 255 chars |
firstName | string | ✅ | Max 100 chars |
middleName | string | Max 100 chars | |
lastName | string | ✅ | Max 100 chars |
dateOfBirth | string | ✅ | YYYY-MM-DD format |
country | string | ✅ | ISO 3166-1 alpha-2 |
phoneNumber | string | ✅ | Max 20 chars. US: XXXXXXXXXX, 1XXXXXXXXXX, or +1XXXXXXXXXX |
taxId | string | ✅ | Last 4 digits of SSN (min 4 chars) |
address.line1 | string | ✅ | Max 255 chars |
address.line2 | string | Max 255 chars | |
address.city | string | ✅ | Max 100 chars |
address.state | string | Max 100 chars | |
address.postalCode | string | XXXXX or XXXXX-YYYY | |
address.country | string | ✅ | ISO 3166-1 alpha-2 |
document.type | string | ✅ | See supported types below |
document.frontImageUrl | string | ✅ | URL of front image. Max 2048 chars |
document.backImageUrl | string | URL of back image. Optional for passport | |
document.documentNumber | string | ✅ | e.g. passport number. Max 50 chars |
consent.termsAcceptedAt | integer | ✅ | Epoch timestamp in ms of T&C acceptance |
consent.ipAddress | string | ✅ | IPv4 or IPv6 address of the user |
consent.userAgent | string | User agent string of the user's browser. Max 500 chars |
Supported document types:
| Value | Document |
|---|---|
DRIVERS_LICENSE | Driver's License |
PASSPORT | Passport |
NATIONAL_ID | National ID Card |
PASSPORT_CARD | Passport Card |
RESIDENCE_PERMIT | Residence Permit |
PERMANENT_RESIDENCE_CARD | Permanent Residence Card |
Step 2 — Your Internal KYC Review
Run your own internal compliance review on the submitted data. The Breeze integration is asynchronous — only call the Breeze API once your internal review is approved. The integration is compatible with your existing compliance workflow.
Step 3 — Submit KYC to Breeze
Call the Submit Headless KYC API to submit KYC data to Breeze.
Only
TIER_2KYC is supported. This endpoint is idempotent oncustomerReferenceId.
Breeze runs automated PEP & sanctions screening and returns one of the following statuses:
| Status | Meaning |
|---|---|
approved | Customer passes all checks and is ready to receive payouts |
pending | Queued for processing |
processing | Identity verification in progress |
under_review | Flagged for manual review; payouts queued until resolved (<24h SLA) |
rejected | Fails compliance (e.g. sanctions match); no payouts permitted |
Resolution times:
- Automated cases: ~1 minute
- Escalated cases: resolved within 24 hours
If Breeze requires additional information, it will contact the customer directly or route the request through your compliance/ops team. Aligning your internal compliance checks with Breeze's requirements upfront will minimise the volume of manual review cases.
Customer object creation
Submitting KYC via this endpoint also creates a Customer object in Breeze.
- The
data.customerIdfield in the API response and webhook payload is your customer's Breeze ID- The
data.customerReferenceIdfield in the API response and webhook payload is your user record's identifier.You can choose to pass in either when creating a Payout Page.
Step 4 — Handling Updates from Breeze
Breeze sends a HEADLESS_KYC_STATUS_UPDATED webhook to your configured webhook endpoint whenever the KYC status of a customer changes (e.g. from processing to approved, or to under_review).
Payload
{
"type": "HEADLESS_KYC_STATUS_UPDATED",
"signature": "<webhook_signature>",
"data": {
"id": "<headless_kyc_request_id>",
"customerId": "<breeze_customer_id>",
"accountId": "<breeze_account_id>",
"kycId": "<persona_kyc_id>",
"kycStatus": "approved",
"customerReferenceId": "<your_unique_user_id>",
"tier": "TIER_2",
"rejectionReason": null,
"createdAt": 1710000000000,
"updatedAt": 1710000001000
}
}Payload Fields
| Field | Type | Notes |
|---|---|---|
type | string | Always HEADLESS_KYC_STATUS_UPDATED |
signature | string | HMAC signature for verifying the webhook payload. See Webhook Signature Verification |
data.id | string | Breeze's ID for this KYC request |
data.customerId | string | Breeze's ID for the customer |
data.accountId | string | Breeze account ID associated with the merchant |
data.kycId | string | ID of the KYC record with Breeze's identity verification provider |
data.kycStatus | string | Current KYC status — see KYC statuses |
data.customerReferenceId | string | Your unique reference ID for this customer |
data.tier | string | Always TIER_2 for Headless KYC |
data.rejectionReason | string | Populated if kycStatus is rejected |
data.createdAt | number | Epoch timestamp (ms) when the KYC request was created |
data.updatedAt | number | Epoch timestamp (ms) of the most recent status update |
Use the data.kycStatus field to determine how to respond:
The customer has passed all identity and compliance checks and is ready to receive payouts.
Recommended action: Unlock payout capability for the customer in your UI and proceed to trigger a payout.
{
"type": "HEADLESS_KYC_STATUS_UPDATED",
"signature": "<webhook_signature>",
"data": {
"id": "<headless_kyc_request_id>",
"customerId": "<breeze_customer_id>",
"accountId": "<breeze_account_id>",
"kycId": "<persona_kyc_id>",
"kycStatus": "approved",
"customerReferenceId": "<your_unique_user_id>",
"tier": "TIER_2",
"rejectionReason": null,
"createdAt": 1710000000000,
"updatedAt": 1710000001000
}
}Always verify the
signaturefield before processing any webhook payload. See Webhook Signature Verification for details.
Polling for KYC Status
Alternatively, you can also check the status of a KYC submission at any time using the customer's reference ID: 📄 API Reference — Get a KYC request by customer reference ID
Step 5 — Notify Your User (Your UI)
Once both your internal KYC approval and Breeze's KYC approval have cleared, notify your user that their payout capability is available. You handle this notification entirely within your own UI.
What's Next
Once your customers are KYC-approved, proceed to the Payout Page integration to start disbursing funds. Breeze offers two payout options:
- Hosted Payout Page — Breeze hosts the payout UI. Because KYC is already cleared, your users will skip the identity verification step and proceed directly to payout. See Payout Page Overview.
- Headless Payout API — Trigger payouts entirely via API with no Breeze-hosted UI. Note that this option is only available to merchants specifically enabled by the Breeze team. See Headless Payout to get started.
Updated 1 day ago
