Skip to main content

KYC / KYB

The KYC / KYB (Know Your Customer / Know Your Business) capability verifies the identity of agents, humans, and businesses participating in the ItPay ecosystem. Verification levels gate payment limits — higher levels unlock higher transaction amounts, more payment channels, and lower fees.


Swimlane Diagram — Identity Verification Flow

┌──────────┐ ┌──────────────┐ ┌──────────┐ ┌──────────┐
│ Human │ │ Agent │ │ ItPay │ │ Channel │
│ (Payer) │ │ (Buyer) │ │ Protocol │ │ (Alipay) │
└────┬─────┘ └──────┬───────┘ └────┬─────┘ └────┬─────┘
│ │ │ │
│ (1) Initiate │ │ │
│ KYC Upgrade │ │ │
│ ─────────────────▶ │ │
│ "I want to │ │ │
│ increase my │ │ │
│ payment limit │ │ │
│ to $100/transaction" │ │
│ │ │ │
│ │ (2) POST /v1/kyc/verify │
│ │ ─────────────────▶ │
│ │ { level: "basic", │
│ │ data: { email, phone } } │
│ │ │ │
│ │ │ (3) OTP │
│ (4) Receive OTP │ │ Challenge │
│ ◄────────────────│◄─────────────────│ │
│ "Enter the 6-digit code │ │
│ sent to your phone/email" │ │
│ │ │ │
│ (5) Submit OTP │ │ │
│ ─────────────────▶ │ │
│ │ (6) Forward │ │
│ │ OTP + Verify │ │
│ │ ─────────────────▶ │
│ │ │ │
│ │ │ (7) Channel │
│ │ │ KYC Check │
│ │ │ ───────────────▶
│ │ │ │
│ │ │ ◄──────────────│
│ │ │ Alipay L1 OK │
│ │ │ │
│ │ (8) 201 Created │ │
│ │ ◄────────────────│ │
│ │ { status: │ │
│ │ "pending" } │ │
│ │ │ │
│ │ (9) Webhook: │ │
│ │ kyc.verified │ │
│ │ ◄────────────────│ │
│ │ │ │
│ (10) Confirmed │ │ │
│ ◄────────────────│ │ │
│ "You're now at │ │ │
│ Level 1 — │ │ │
│ you can pay up │ │ │
│ to $100/transaction!" │ │
│ │ │ │

Level Upgrade (L1 → L2 → L3)

┌──────────┐ ┌──────────────┐ ┌──────────┐ ┌──────────┐
│ Human │ │ Agent │ │ ItPay │ │ Channel │
│ (Payer) │ │ (Buyer) │ │ Protocol │ │ (Alipay) │
└────┬─────┘ └──────┬───────┘ └────┬─────┘ └────┬─────┘
│ │ │ │
│ L1→L2 Upgrade │ │ │
│ ─────────────────▶ │ │
│ "I need to pay │ │ │
│ $500 for a │ │ │
│ subscription" │ │ │
│ │ │ │
│ │ POST /v1/kyc/verify │
│ │ { level: "enhanced", │
│ │ data: { document_type, │
│ │ document_number, country } } │
│ │ ─────────────────▶ │
│ │ │ │
│ │ ┌─ Document Verification ────┐ │
│ │ │ Step 1: Validate document │ │
│ │ │ format & number │ │
│ │ │ Step 2: Cross-reference │ │
│ │ │ with issuing auth │ │
│ │ │ Step 3: Match name + DOB │ │
│ │ └────────────────────────────┘ │
│ │ │ │
│ │ REJECTED │ │
│ │ ◄────────────────│ │
│ "Document │ │ │
│ verification │ │ │
│ failed. │ │ │
│ Please re- │ │ │
│ submit a │ │ │
│ valid passport │ │ │
│ or national ID"│ │ │
│ ◄────────────────│ │ │
│ │ │ │
│ Re-submit │ │ │
│ corrected docs │ │ │
│ ─────────────────▶ │ │
│ │ │ │
│ │ POST /v1/kyc/verify │
│ │ { level: "enhanced", │
│ │ data: { updated docs } } │
│ │ ─────────────────▶ │
│ │ │ │
│ │ kyc.verified │ │
│ │ ◄────────────────│ │
│ "Congratulations! You're now at │ │
│ Level 2 — $1000/transaction limit" │
│ ◄────────────────│ │ │
│ │ │ │

Payment Gating by KYC Level

┌──────────┐ ┌──────────────┐ ┌──────────┐ ┌──────────┐
│ Human │ │ Agent │ │ ItPay │ │ Channel │
│ (Payer) │ │ (Buyer) │ │ Protocol │ │ (Alipay) │
└────┬─────┘ └──────┬───────┘ └────┬─────┘ └────┬─────┘
│ │ │ │
│ "I want to pay │ │ │
│ $50 using │ │ │
│ Alipay" │ │ │
│ ─────────────────▶ │ │
│ │ │ │
│ │ POST /v1/payments │
│ │ { amount: 50, │
│ │ kyc_level: 0 } │
│ │ ─────────────────▶ │
│ │ │ │
│ │ │ 403 │
│ │ ◄────────────────│ │
│ │ INSUFFICIENT_KYC │ │
│ │ "Level 0 max │ │
│ │ is $10/txn. │ │
│ │ Upgrade to │ │
│ │ Level 1 for │ │
│ │ $100/txn cap." │ │
│ "You need to │ │ │
│ verify your │ │ │
│ identity first │ │ │
│ — max $10 │ │ │
│ without KYC" │ │ │
│ ◄────────────────│ │ │
│ │ │ │

Detailed Interaction Trace

Step 1: Human Initiates KYC Upgrade

The human tells their agent they want higher payment limits. The agent constructs a KYC verification request.

Human dialog:

"I want to increase my payment limit. I need to pay $50 for a premium report — can you verify my identity?"

Agent decision: The agent checks current KYC level (Level 0 — $10/txn limit). Since the desired payment ($50) exceeds Level 0, the agent initiates basic (Level 1) KYC.

Step 2: Agent Submits KYC Verification (Basic — Level 1)

HTTP Request:

POST /v1/kyc/verify
Content-Type: application/json
Authorization: Bearer api_key_merchant_abc123
{
"agent_id": "agent_cli_a1b2c3d4",
"level": "basic",
"data": {
"email": "user@example.com",
"phone": "+861****8000"
}
}

Error handling — invalid data:

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
"error": {
"code": "validation_error",
"message": "Phone number is required for basic verification",
"details": {
"field": "data.phone",
"reason": "missing_field"
}
}
}

Human dialog (error):

"Your phone number is missing. Please provide a valid phone number where you can receive SMS."

Step 3: ItPay Issues OTP Challenge

ItPay creates the verification request in pending state and sends OTPs to the provided email and phone.

HTTP Response (initial):

HTTP/1.1 201 Created
Content-Type: application/json

{
"verification_id": "kyc_01J7Z4A5B6C7D8E9F0G1H2I3J",
"agent_id": "agent_cli_a1b2c3d4",
"level": "basic",
"status": "pending",
"challenge": {
"type": "otp",
"channels": ["email", "sms"],
"expires_at": "2026-05-27T09:45:00Z"
},
"created_at": "2026-05-27T09:35:00Z",
"updated_at": "2026-05-27T09:35:00Z"
}

Human dialog:

"I've sent a 6-digit verification code to your email (user@example.com) and phone (+861****8000). Please check them and enter the code to proceed."

Step 4: Human Submits OTP

The human retrieves the OTP and provides it to the agent, who forwards it to ItPay.

HTTP Request (OTP verification):

POST /v1/kyc/verify
Content-Type: application/json
Authorization: Bearer api_key_merchant_abc123

{
"verification_id": "kyc_01J7Z4A5B6C7D8E9F0G1H2I3J",
"otp": "482931"
}

Error handling — wrong OTP:

HTTP/1.1 401 Unauthorized
Content-Type: application/json

{
"error": {
"code": "invalid_otp",
"message": "The provided OTP is incorrect or has expired",
"details": {
"attempts_remaining": 2,
"retry_after_seconds": 30
}
}
}

Human dialog (wrong OTP):

"That code isn't correct. You have 2 more attempts before a new code needs to be sent. Please check your messages again."

Step 5: Channel KYC Cross-Reference

ItPay checks whether the human is already verified on any supported payment channel (e.g., Alipay real-name verified). If so, it may expedite or skip parts of the verification.

Internal ItPay processing:

{
"channel_check": {
"alipay": {
"user_found": true,
"kyb_level": "real_name_verified",
"equivalent_to": "basic"
},
"wechat": {
"user_found": true,
"kyb_level": "real_name_verified",
"equivalent_to": "basic"
}
},
"friction_reduction_applied": true,
"expedited": true
}

Step 6: Verification Approved

ItPay processes the verification and emits a webhook event.

Webhook:

POST https://merchant.example.com/webhooks/itpay
Content-Type: application/json
ItPay-Signature: t=1716801000,v1=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0

{
"type": "kyc.verified",
"data": {
"verification_id": "kyc_01J7Z4A5B6C7D8E9F0G1H2I3J",
"agent_id": "agent_cli_a1b2c3d4",
"level": "basic",
"previous_level": "anonymous",
"limits": {
"daily": { "value": 1000, "currency": "USD" },
"per_transaction": { "value": 100, "currency": "USD" }
},
"channels": ["alipay", "wechat", "promptpay", "paynow"]
},
"created_at": "2026-05-27T09:36:00Z"
}

Human dialog (success):

"Great news! Your identity has been verified at Level 1 (Basic). You can now make transactions up to $100 each, with a daily limit of $1,000. Alipay and WeChat are available as payment channels."

Step 7: Upgrade to Enhanced (Level 2) — Document Submission

Human requests a higher limit. Agent submits enhanced KYC with government ID documents.

HTTP Request:

POST /v1/kyc/verify
Content-Type: application/json
Authorization: Bearer api_key_merchant_abc123

{
"agent_id": "agent_cli_a1b2c3d4",
"level": "enhanced",
"data": {
"email": "user@example.com",
"phone": "+861****8000",
"country": "CN",
"full_name": "Zhang Wei",
"document_type": "national_id",
"document_number": "110101199001011234"
}
}

3-Step Verification Process:

StepActionDescriptionExpected Duration
1Document format validationChecks that document number follows country-specific format (e.g., 18-digit CN ID)< 1 second
2Issuing authority cross-referenceValidates document against government databases or trusted third-party KYC providers1–30 seconds
3Identity matchVerifies name, date of birth, and face (if photo ID) match the provided details10–60 seconds

Human dialog (document upload):

"For Level 2 (Enhanced), I need you to provide a government-issued ID. A national ID, passport, or driver's license will work. Please upload a clear photo of the front and back."

Step 8: Rejection Scenario

If document verification fails, the system returns a rejection.

HTTP Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
"verification_id": "kyc_01J7Z4B6C7D8E9F0G1H2I3J4K",
"agent_id": "agent_cli_b2c3d4e5",
"level": "enhanced",
"status": "rejected",
"rejection_reason": {
"code": "document_mismatch",
"message": "The submitted document number does not match the provided name and date of birth",
"details": "The name 'Zhang Wei' on the application does not match the registered name 'Wang Wei' on document number 110101199001011234"
}
}

Webhook (rejection):

{
"type": "kyc.rejected",
"data": {
"verification_id": "kyc_01J7Z4B6C7D8E9F0G1H2I3J4K",
"agent_id": "agent_cli_b2c3d4e5",
"level": "enhanced",
"rejection_reason": {
"code": "document_mismatch",
"message": "Name does not match document"
},
"appeal_available": true,
"appeal_url": "https://itpay.ai/kyc/appeal/kyc_01J7Z4B6C7D8E9F0G1H2I3J4K"
}
}

Human dialog (rejection):

"The identity verification didn't pass. The name on your application doesn't match your ID document. You can either:

  1. Re-submit with the correct document matching your registered name
  2. File an appeal at https://itpay.ai/kyc/appeal if you believe this is an error"

Step 9: Appeal Flow

The human can appeal a rejection. This submits the existing verification data to a manual review queue.

HTTP Request (appeal):

POST /v1/kyc/appeal
Content-Type: application/json
Authorization: Bearer api_key_merchant_abc123

{
"verification_id": "kyc_01J7Z4B6C7D8E9F0G1H2I3J4K",
"reason": "My legal name was updated after marriage. I have attached my marriage certificate and updated ID. The document I submitted matches my current legal name."
}

HTTP Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
"appeal_id": "appl_01K2L3M4N5O6P7Q8R9S0T1U2V",
"verification_id": "kyc_01J7Z4B6C7D8E9F0G1H2I3J4K",
"status": "under_review",
"estimated_resolution": "2026-05-29T09:40:00Z",
"message": "Your appeal has been submitted. A compliance officer will review within 48 hours."
}

Human dialog (appeal):

"Thanks for explaining. I've submitted your appeal with the supporting documents. A compliance team member will review it within 48 hours. Your current KYC level (Basic — $100/txn) remains active during the review."

Step 10: Upgrade to Business (Level 3) — Full KYB

For businesses needing high limits ($10,000/txn) and access to USDC/stablecoin channels.

Human dialog:

"I'm registering my business 'SummaryBot Inc.' for Level 3. I'll need to provide our business registration documents and UBO (Ultimate Beneficial Owner) declaration."

HTTP Request:

POST /v1/kyc/verify
Content-Type: application/json
Authorization: Bearer api_key_merchant_abc123

{
"agent_id": "agent_srv_9x8y7z6w",
"level": "business",
"data": {
"email": "legal@summarybot.ai",
"phone": "+165****1234",
"country": "US",
"full_name": "Jane Smith",
"business_name": "SummaryBot Inc.",
"registration_number": "US-123456789",
"ubo_declaration": {
"full_name": "Jane Smith",
"ownership_pct": 100
}
}
}

HTTP Response:

HTTP/1.1 201 Created
Content-Type: application/json

{
"verification_id": "kyc_01J7Z4C7D8E9F0G1H2I3J4K5L",
"agent_id": "agent_srv_9x8y7z6w",
"level": "business",
"status": "pending",
"limits": {
"daily": { "value": 100000, "currency": "USD" },
"per_transaction": { "value": 10000, "currency": "USD" }
},
"channels": ["alipay", "wechat", "promptpay", "paynow", "duitnow", "vietqr", "gcash", "usdc"],
"compliance_review_required": true,
"estimated_review_time_hours": 72,
"created_at": "2026-05-27T09:45:00Z",
"updated_at": "2026-05-27T09:45:00Z"
}

Human dialog (pending review):

"Your business verification (Level 3) has been submitted. This requires a compliance review that typically takes up to 72 hours. Meanwhile, your current Enhanced level limits ($1,000/txn) remain active. You'll be notified when the review is complete."

Level-to-Limit Mapping Reference

KYC LevelPer-Transaction CapDaily CapChannelsTiers Above
0 (Anonymous)$10$100Alipay, WeChat (limited)
1 (Basic)$100$1,000All consumerEmail + Phone OTP
2 (Enhanced)$1,000$10,000All consumer + selected businessGov ID + Address
3 (Business)$10,000$100,000All + USDC/stablecoinFull KYB + UBO

Payment Gating — Error Response

When a payment attempt exceeds the current KYC level's limit:

HTTP/1.1 403 Forbidden
Content-Type: application/json

{
"error": {
"code": "INSUFFICIENT_KYC",
"message": "Payment amount exceeds KYC level limit",
"details": {
"current_kyc_level": "anonymous",
"current_txn_limit": { "value": 10, "currency": "USD" },
"requested_amount": { "value": 50, "currency": "USD" },
"required_kyc_level": "basic",
"upgrade_url": "/v1/kyc/verify"
}
}
}

Endpoint

MethodEndpointDescription
POST/v1/kyc/verifySubmit identity verification data

Verification Levels

LevelNameDaily Limit (USD)Per-Transaction Limit (USD)ChannelsDescription
0Anonymous$100$10Alipay, WeChat (limited)No verification required. Basic QR payments only.
1Basic$1,000$100All consumer channelsEmail and phone verification.
2Enhanced$10,000$1,000All consumer + selected business channelsGovernment ID verification + address proof.
3Business$100,000$10,000All channels including USDC/stablecoinFull KYB — business registration, UBO declaration, compliance review.

Request Fields

FieldTypeRequiredDescription
agent_idstringyesThe agent or entity being verified
levelstringyesTarget verification level — anonymous, basic, enhanced, or business
dataobjectconditionalVerification data. Required fields depend on the target level.
data.emailstringbasic+Email address for OTP verification
data.phonestringbasic+Phone number for SMS OTP verification
data.countrystringenhanced+ISO 3166-1 alpha-2 country code of residence/registration
data.full_namestringenhanced+Legal full name of the individual
data.document_typestringenhanced+ID document type — passport, national_id, drivers_license
data.document_numberstringenhanced+ID document number
data.business_namestringbusinessLegal business name
data.registration_numberstringbusinessBusiness registration or tax ID
data.ubo_declarationobjectbusinessUltimate Beneficial Owner declaration
data.ubo_declaration.full_namestringbusinessUBO full name
data.ubo_declaration.ownership_pctnumberbusinessOwnership percentage
channel_credentialsobjectnoPre-existing channel verification credentials to reduce friction
channel_credentials.alipay_user_idstringnoAlipay user ID (for Alipay-verified users)
channel_credentials.wechat_open_idstringnoWeChat Open ID (for WeChat-verified users)

Request Example — Basic (Level 1)

POST /v1/kyc/verify
Content-Type: application/json
Authorization: Bearer ***

{
"agent_id": "agent_cli_a1b2c3d4",
"level": "basic",
"data": {
"email": "user@example.com",
"phone": "+861****8000"
}
}

Response Example — Basic

HTTP/1.1 201 Created
Content-Type: application/json

{
"verification_id": "kyc_01J7Z4A5B6C7D8E9F0G1H2I3J",
"agent_id": "agent_cli_a1b2c3d4",
"level": "basic",
"status": "pending",
"data": {
"email": "user@example.com",
"phone": "+861****8000"
},
"limits": {
"daily": { "value": 1000, "currency": "USD" },
"per_transaction": { "value": 100, "currency": "USD" }
},
"channels": ["alipay", "wechat", "promptpay", "paynow"],
"created_at": "2026-05-27T09:35:00Z",
"updated_at": "2026-05-27T09:35:00Z"
}

Request Example — Enhanced (Level 2) with Channel Credentials

POST /v1/kyc/verify
Content-Type: application/json
Authorization: Bearer ***

{
"agent_id": "agent_cli_b2c3d4e5",
"level": "enhanced",
"data": {
"email": "verified@example.com",
"phone": "+861****9000",
"country": "CN",
"full_name": "Zhang Wei",
"document_type": "national_id",
"document_number": "110101199001011234"
},
"channel_credentials": {
"alipay_user_id": "alipay_usr_abc_123",
"wechat_open_id": "wx_openid_xyz_789"
}
}

Response Example — Enhanced

HTTP/1.1 201 Created
Content-Type: application/json

{
"verification_id": "kyc_01J7Z4B6C7D8E9F0G1H2I3J4K",
"agent_id": "agent_cli_b2c3d4e5",
"level": "enhanced",
"status": "pending",
"limits": {
"daily": { "value": 10000, "currency": "USD" },
"per_transaction": { "value": 1000, "currency": "USD" }
},
"channels": ["alipay", "wechat", "promptpay", "paynow", "duitnow", "vietqr", "gcash"],
"channel_friction_reduced": true,
"friction_reduction_channels": ["alipay", "wechat"],
"created_at": "2026-05-27T09:40:00Z",
"updated_at": "2026-05-27T09:40:00Z"
}

Request Example — Business / KYB (Level 3)

POST /v1/kyc/verify
Content-Type: application/json
Authorization: Bearer ***

{
"agent_id": "agent_srv_9x8y7z6w",
"level": "business",
"data": {
"email": "legal@summarybot.ai",
"phone": "+165****1234",
"country": "US",
"full_name": "Jane Smith",
"business_name": "SummaryBot Inc.",
"registration_number": "US-123456789",
"ubo_declaration": {
"full_name": "Jane Smith",
"ownership_pct": 100
}
}
}

Response Example — Business

HTTP/1.1 201 Created
Content-Type: application/json

{
"verification_id": "kyc_01J7Z4C7D8E9F0G1H2I3J4K5L",
"agent_id": "agent_srv_9x8y7z6w",
"level": "business",
"status": "pending",
"limits": {
"daily": { "value": 100000, "currency": "USD" },
"per_transaction": { "value": 10000, "currency": "USD" }
},
"channels": ["alipay", "wechat", "promptpay", "paynow", "duitnow", "vietqr", "gcash", "usdc"],
"created_at": "2026-05-27T09:45:00Z",
"updated_at": "2026-05-27T09:45:00Z"
}

State Machine

Each verification request follows this lifecycle:

┌─────────────┐
│ unverified │
└──────┬──────┘
│ submit verification

┌─────────────┐
│ pending │
└──────┬──────┘
┌─────┴─────┐
│ │
▼ ▼
┌─────────┐ ┌─────────┐
│ verified │ │ rejected│
└─────────┘ └─────────┘

Transitions

FromToTrigger
unverifiedpendingVerification data submitted
pendingverifiedIdentity verification successful
pendingrejectedIdentity verification failed (invalid documents, data mismatch)
verifiedrejectedPeriodic review found issues or documents expired
rejectedpendingRe-submit with corrected data

OAuth-Based Friction Reduction

When the payer already has a verified identity on a supported payment channel (e.g., Alipay real-name verified), those credentials can be reused to skip or accelerate the ItPay KYC process.

How It Works

  1. The agent includes channel_credentials in the KYC request.
  2. ItPay cross-references the channel credentials with the channel's KYC status.
  3. If the channel has already performed equivalent or higher-level verification, ItPay may:
    • Expedite the verification (reduced review time from days to minutes)
    • Reduce friction (skip some document uploads)
    • Accept directly (for Level 1 basic, if the channel KYC is equivalent)
  4. The response field channel_friction_reduced indicates whether channel credentials were used to reduce friction.

Supported Channels for Friction Reduction

ChannelLevel EquivalentNotes
AlipayBasic (Level 1)Real-name verified users can skip email/phone OTP
WeChat PayBasic (Level 1)Real-name verified users can skip email/phone OTP
PromptPay (Thailand)Basic (Level 1)National ID-linked accounts
PayNow (Singapore)Basic (Level 1)NRIC/FIN-linked accounts

Key Behaviors

  • Progressive verification: An agent can start at any level and upgrade later by submitting a new verification request with a higher level.
  • Channel limits: Unverified (Level 0) agents can only use limited channels and are capped at $10 per transaction. Higher levels unlock more channels and higher limits.
  • Document retention: Submitted verification documents are stored encrypted for compliance purposes. Retention follows applicable regulations (typically 5–7 years).
  • Periodic review: Enhanced (Level 2) and Business (Level 3) verifications are subject to periodic re-verification (annually for Level 2, semi-annually for Level 3).

Webhook Events

EventDescription
kyc.verifiedVerification was approved at the requested level
kyc.rejectedVerification was rejected (includes reason in payload)
kyc.expiringVerification is nearing its expiration date (sent 30 days before)
kyc.expiredVerification period has ended, limits have been downgraded

Next Steps