KYB Verification Guide

KYB Verification Guide

UrbanPayX verifies the businesses you register, either through its own hosted flow or by recording a result you obtained elsewhere. This guide covers both verification modes, step-by-step flows, status transitions, and resubmission.

The subject of every KYB flow is a business customer: a company record owned by your account, identified by company_name, registration_number, and country.


Why verify

AML rules generally require you to know which company you are moving money for. UrbanPayX gives you the verification tooling and stores the outcome, but it does not enforce it: no endpoint checks kyb_status. Where verification sits in your flow, and what you do with a rejected result, is your decision.


Two verification modes

Every business customer carries a verification_mode:

ModeWhat it means
urbanpayx_kybUrbanPayX runs the check. You get a hosted verification link, the business submits its documents there, and the decision drives kyb_status.
external_attestationYou verify the business yourself and report the outcome. UrbanPayX stores the status, provider label, and reference; it runs no check of its own.

If you omit verification_mode on create, your account default applies. A business can only be acted on through the endpoint that matches its mode: initiating managed KYB on an external_attestation business, or posting an external status on a urbanpayx_kyb business, returns 400.


UrbanPayX KYB flow

Step 1 - Create the business customer

curl -X POST https://api-sandbox.urbanpayx.com/api/v1/kyb/businesses \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "company_name": "Example Trading SL",
    "registration_number": "B12345678",
    "country": "ESP",
    "legal_address": "Calle Mayor 1, 28013 Madrid",
    "tax_id": "ESB12345678",
    "contact_email": "[email protected]",
    "kyb_level": "standard"
  }'

company_name, registration_number, and country (ISO 3166-1 alpha-3) are required; everything else is optional. The call is idempotent on (registration_number, country): if the business already exists it is returned unchanged rather than duplicated.

kyb_level picks which set of checks runs. Call GET /kyb/levels for the keys available to your account, including any custom workflows you built. Omit it to use your account default.

Step 2 - Initiate verification

curl -X POST https://api-sandbox.urbanpayx.com/api/v1/kyb/verify \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "company_name": "Example Trading SL",
    "registration_number": "B12345678",
    "country": "ESP",
    "callback_url": "https://yourapp.com/kyb/done",
    "send_email": true
  }'

The endpoint takes the same identity fields as create and registers the business if it does not exist yet, so you can skip Step 1 for a brand-new business. The level comes from the business record (or your account default), not from this request.

{
  "business_customer_id": "bc_...",
  "kyb_status": "pending",
  "verification_url": "https://verify.urbanpayx.com/...",
  "message": "KYB verification initiated"
}
  • verification_url is the hosted link the business opens to submit documents. Calling the endpoint again while a verification is in progress returns the existing link instead of starting a second one.
  • callback_url is where the business is redirected when it finishes. It must be HTTPS. Omit it to use your account's default verification callback URL.
  • send_email: true emails the link to the business contact_email for you. Omit the field to use your account default.

Step 3 - The business completes verification

The business opens the link and submits its registry details and documents. Nothing is required from you during this step.

Step 4 - Receive the result

The decision arrives as a kyb.status_changed webhook. Two pull-based fallbacks exist for a missed webhook:

EndpointUse it for
GET /kyb/status/{business_id}Current kyb_status and the latest verification link.
GET /kyb/decision/{business_id}The full decision, reconciling kyb_status on demand.
GET /kyb/detail/{business_id}The latest curated verification record (extracted company data and check outcomes).
GET /kyb/detail/{business_id}/historyEvery verification record for the business.
GET /kyb/detail/{business_id}/documents/{file_role}Download a document the business submitted.

Status transitions

none --> pending --> approved
              |
              +----> rejected
approved --> on_hold        (ongoing monitoring)
kyb_statusMeaning
noneCreated but verification not yet initiated.
pendingA verification session is open; awaiting the decision.
approvedThe business passed.
rejectedThe business failed.
on_holdA previously approved business placed under review by ongoing monitoring.

External attestation flow

Step 1 - Create the business

Same as above, with "verification_mode": "external_attestation".

Step 2 - Verify through your own process

Run whatever checks your compliance policy requires, with whichever provider you use.

Step 3 - Report the result

curl -X POST https://api-sandbox.urbanpayx.com/api/v1/kyb/external/status/bc_... \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "verified",
    "provider": "your-provider-name",
    "reference": "case-12345",
    "reason": "Registry and UBO check passed"
  }'

status is pending, verified, or rejected and drives external_verification_status; kyb_status stays none for these businesses. provider, reference, reason, and a free-form payload object are optional and stored for your audit trail.


Switching verification modes

curl -X PATCH https://api-sandbox.urbanpayx.com/api/v1/kyb/businesses/bc_.../verification-mode \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"verification_mode": "external_attestation"}'

Switching clears the verification source unless the business is already approved or verified, in which case the existing result is kept.


Editing and deactivating

PATCH /kyb/businesses/{business_id} updates company_name, legal_address, tax_id, and contact_email. Identity fields lock once the business has been verified, so a change to a locked field returns 409.

POST /kyb/businesses/{business_id}/deactivate soft-deletes the business (is_active=false) and requires a reason of at least 10 characters, recorded in your audit log. POST /kyb/businesses/{business_id}/activate reverses it. Both are restricted to OWNER.


Resubmission

When a verification fails on fixable steps (an unreadable document, a missing file), ask the business to redo just those steps on the same session instead of starting a new one:

curl -X POST https://api-sandbox.urbanpayx.com/api/v1/kyb/bc_.../resubmit \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

No body. Allowed while kyb_status is pending or rejected. The response returns session_url for the business to reopen and resubmit_steps listing what it must redo. Reusing the session means the resubmission is not billed as a second verification.


Listing businesses

curl "https://api-sandbox.urbanpayx.com/api/v1/kyb/businesses?page=1&page_size=20&effective_status=approved" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Filters: kyb_status, effective_status, verification_mode, external_verification_status, q (free-text search), and include_inactive. Use effective_status when you want one filter that covers both modes: it resolves external_attestation businesses to their external_verification_status. Deactivated businesses are excluded unless you pass include_inactive=true.

GET /kyb/summary returns counts per status for a dashboard tile.


Verification and payments

Payment initiation does not check verification state. A business whose kyb_status is none, pending, rejected, or on_hold can be paid for exactly like an approved one, and there is no verification-related error code on the payment endpoint.

If you want an approved-only policy, read kyb_status (or external_verification_status for externally attested businesses) and gate the call in your own code. The kyb.status_changed webhook is the cheapest way to keep that state fresh.


API endpoints reference

MethodPathDescription
POST/kyb/businessesCreate a business customer
GET/kyb/businessesList business customers (paginated)
PATCH/kyb/businesses/{business_id}Update a business's details
PATCH/kyb/businesses/{business_id}/verification-modeSwitch verification mode
POST/kyb/businesses/{business_id}/activateReactivate a business
POST/kyb/businesses/{business_id}/deactivateDeactivate a business
POST/kyb/verifyInitiate UrbanPayX KYB verification
POST/kyb/external/status/{business_id}Report an external verification result
GET/kyb/status/{business_id}Get current verification status
GET/kyb/decision/{business_id}Full decision, reconciled on demand
GET/kyb/detail/{business_id}Latest curated verification record
GET/kyb/detail/{business_id}/historyAll verification records
GET/kyb/detail/{business_id}/documents/{file_role}Download a submitted document
POST/kyb/{business_customer_id}/resubmitAsk the business to redo failed steps
GET/kyb/levelsList verification levels available
GET/kyb/summaryCount businesses by verification status

Related guides