Z Zise Developers 简体中文
Account Center › Guides

Merchants upload files and submit L2 parameters directly, then query reviews and supplementary requests—all without a hosted page.

L2 Advanced Verification OpenAPI Integration for Downstream Merchants

For merchant Apps and custom clients: the merchant collects information, and its server calls the OpenAPI to upload files, submit JSON, and query review results and supplementary requests. No hosted page is required at any stage.

1. Members and Verification Levels

First create a member through POST /v1/members, then complete the member's own L1 review. Only an approved primary L1 profile qualifies for L2. Quick KYC is a separate binding of card issuance information and does not raise the member's actual verification level. An L0 member bound to Quick KYC remains L0 and may obtain cards subject to product rules, but cannot directly apply for L2.

Successful L2 submission means the application is under review; it does not immediately enable services requiring L2. After L2 approval, query the member's status before using Global Remittance APIs. Remittances remain subject to merchant service switches, product rules, and transaction validation.

2. Call Sequence

StepEndpointPermission
Query eligibility and enum optionsGET /v1/kyc/l2/configkyc:read
Upload supporting files individuallyPOST /v1/kyc/fileskyc:write
Submit L2 informationPOST /v1/kyc/l2/applicationskyc:write
Query the latest L2 applicationGET /v1/kyc/l2/applicationskyc:read
Query the member's verification levelGET /v1/kyckyc:read
Query pending supplements and field templatesGET /v1/kyc/supplementskyc:read
Submit supplementary parametersPOST /v1/kyc/supplements/{id}kyc:write

Use the environment domain provided in your integration configuration. Append the paths below to that domain; never store merchant API Keys or signing keys in the App.

All endpoints above require x-auth-token: Bearer <auth_token> and x-on-behalf-of: <external_member_id 或 mem_会员ID>. Obtain the token through POST /v1/connect/token using x-client-id and x-api-key.

POST requests additionally require x-idempotency-key (one UUID per business submission), x-timestamp (Unix seconds), x-nonce (a new UUID per request), and x-signature. v2 signing is recommended: join the following six lines with newline characters, without a trailing newline, compute HMAC-SHA256 with the merchant signing key, and Base64-encode it:


POST
/v1/kyc/l2/applications
<timestamp>
<nonce>
<请求体原始字节的 SHA-256 小写十六进制>
<SHA-256(x-on-behalf-of + 换行 + x-idempotency-key) 小写十六进制>

Calculate the sixth line from the exact values of the two headers actually sent. The supported legacy v1 signature covers only the first five lines; new integrations should use v2, which also covers the member and idempotency key.

For network retries, retain the same idempotency key, member, and original body, and generate a new timestamp, nonce, and signature. Use a new idempotency key after changing information. Query parameters, when present, are included in the second signature line.

3. Options and Eligibility

GET /v1/kyc/l2/config returns enabled, l1_approved, can_apply, options, currencies, and files. can_apply indicates eligibility at query time; submission revalidates it.

options contains employment_status, industry, job_title, account_purpose, and turnover_monthly, each in the form { "value": "代码", "label": "显示文案" }. Submit value, not label, and do not hard-code the number of options. Use Accept-Language to obtain localized labels.

currencies is the array of currently allowed currencies; files returns max_bytes and formats.

4. Upload Files

Call POST /v1/kyc/files with one file's raw binary bytes as the body and Content-Type: application/octet-stream. This is not multipart, Base64, or an external image URL; calculate the signature over the raw file bytes.

JPEG, PNG, WebP, and PDF are supported, with a maximum of 8 MiB (8,388,608 bytes) per file, based on detected content. Returns HTTP 201:


{ "file_url": "https://<接入域名>/kyc/file/<会员ID>/<文件ID>.pdf" }

Store file_url exactly as returned and use it for L2 or supplementary submissions. The file must have been uploaded for the current member and must still exist. Do not use another member's file, an external URL, or a fabricated nonexistent address.

5. L2 JSON Parameters

POST /v1/kyc/l2/applications, Content-Type: application/json, with a maximum body size of 128 KiB.

In the example below, replace industry and job title with real value entries from the configuration endpoint. Replace file addresses with upload results, and use the actual consent action's timestamp and device information.


{
  "profile": {
    "nickname": "Alex",
    "postal_code": "018956",
    "tax_number": "",
    "employment_status": "Employed",
    "industry": "<options.industry 中所选 value>",
    "job_title": "<options.job_title 中所选 value>",
    "company_name": "Example Ltd",
    "annual_income": "60000.00",
    "account_purpose": ["PURCHASE"],
    "other_purpose": "",
    "banking_countries": ["SG"],
    "banking_currencies": ["USD", "SGD"],
    "internationally": 1,
    "turnover_monthly": "TM001",
    "turnover_monthly_currency": "USD",
    "proof_of_address": "<地址证明 file_url>",
    "source_of_funds": "<资金来源证明 file_url>"
  },
  "tos_acceptance": {
    "accepted": true,
    "ip": "203.0.113.10",
    "user_agent": "<会员实际设备 User-Agent>",
    "accepted_at": "2026-09-24T12:00:00.000Z"
  }
}
profile fieldRequiredRule
nicknameYesString, 1–50 characters
postal_codeYesString, 1–20 characters
tax_numberNoString, up to 100 characters
employment_statusYesCorresponding value from the configuration endpoint
industryYesCorresponding value from the configuration endpoint
job_titleYesCorresponding value from the configuration endpoint
company_nameYes1–100 characters: English letters, digits, spaces, and permitted symbols. Also required for unemployed, student, and retired applicants; provide truthful information satisfying the rules
annual_incomeYesAnnual income in USD, as a positive numeric string, with up to 12 integer digits and 2 decimal places; JSON numbers are not accepted
account_purposeYesNonempty string array using configured values
other_purposeConditionalRequired when OTHERS is included; up to 500 characters
banking_countriesYesNonempty array of two-letter uppercase country/region codes
banking_currenciesYesNonempty array of values from currencies
internationallyNoNumber 0 or 1; defaults to 0. Booleans and strings are not accepted
turnover_monthlyYesMonthly turnover bracket value from configuration
turnover_monthly_currencyYesA value from currencies
proof_of_addressYesAddress proof file_url for the current member
source_of_fundsYesSource of funds proof file_url for the current member
income_proofNoIncome proof file_url for the current member; may be omitted or an empty string
other_proofNoOther supporting file_url for the current member; may be omitted or an empty string

Permitted symbols in company names: . , & ( ) - + % # @ * ! $ ^ _ ? ~ and backslash.

tos_acceptance is required: send accepted: true only after genuine member consent; ip currently supports only the member's IPv4 address; user_agent must be a nonempty string of at most 1000 characters; accepted_at must be the actual consent time in UTC ISO 8601 format (ending in Z, with at most three millisecond digits), no more than 5 minutes ahead of server time. Do not substitute the merchant server's IP, fabricated device details, or fictitious consent records.

Success returns HTTP 201:


{ "id": "kl2_123", "status": "pending" }

A member cannot create another application while one is under review, awaiting supplements, undergoing supplementary review, or approved. After rejection, apply again with a new idempotency key.

6. Query Reviews and Supplements

GET /v1/kyc/l2/applications returns the latest application; application is null if the member has never applied.


{
  "application": {
    "id": "kl2_123",
    "status": "pending",
    "reject_reason": "",
    "created_at": "2026-09-24T12:01:00.000Z",
    "updated_at": "2026-09-24T12:01:00.000Z"
  }
}
statusAction
pendingWait for review
supplement_requiredQuery pending supplements and submit according to the template
supplement_submittedWait for supplementary review
rejectedCorrect the information according to reject_reason and apply again
approvedQuery GET /v1/kyc again to confirm level=2

GET /v1/kyc provides a level overview. Its l2_status pending combines review and supplementary flows; none can also mean all previous applications were rejected. Use the application endpoint above for details. Query again after receiving kyc.result.updated; do not treat the event itself as approval.

Use GET /v1/kyc/supplements for pending supplementary requests. Example entry:


{
  "id": "ksup_456",
  "level": "L2",
  "message": "请补充证明材料",
  "fields": [
    { "index": 0, "label": "资金来源说明", "type": "text", "required": true },
    { "index": 1, "label": "补充证明", "type": "photo", "required": true }
  ],
  "created_at": "2026-09-24T12:05:00.000Z",
  "expires_in_days": 14
}

The actual response is {data: [条目], next_cursor: null, has_more: false} and retains the compatibility field hosted_url, which API-only clients can ignore. The list contains both L1 and L2 entries, distinguished by level. Expiration is 14 days after creation; expires_in_days is a fixed policy, not the remaining number of days.

Upload supplementary proof first, then call POST /v1/kyc/supplements/{id} (the id in this example is ksup_456):


{
  "answers": [
    { "index": 0, "value": "工资收入及储蓄,详见附件" },
    { "index": 1, "value": "<补充证明 file_url>" }
  ]
}

Submit using the server template's index, not a translated label as the field identifier. text allows up to 500 characters; photo uses a file URL uploaded for the current member. required=true fields must be filled; optional fields may be omitted. index values must not repeat or fall outside the template range.

Success returns HTTP 200: {"id":"ksup_456","level":"L2","status":"submitted"}. The request and review state update atomically, entering supplementary review. Retrying unchanged with the same idempotency key returns the original result; resubmitting a completed request with a new key returns state_invalid.

7. Error Handling

codeAction
kyc_requiredComplete the member's own primary L1 review first; Quick KYC does not satisfy this requirement
invalid_fieldsRead key/reason in fields, correct the parameters, and submit with a new idempotency key
state_invalidRequery configuration, application, or supplementary status; it may already be submitted or approved, the supplement may have expired, or the service may be disabled
member_not_found / not_foundCheck member context, merchant ownership, and the supplementary request ID
insufficient_scopeConfigure the necessary permissions for the server credentials
invalid_requestCheck the JSON structure or the 128 KiB body size limit
kyc_upload_invalid / kyc_upload_too_largeCheck the actual file format and 8 MiB limit
idempotency_key_reusedDo not change the member or body for the same idempotency key
idempotency_in_progressThe initial submission is still processing; retry later with the same idempotency key

8. Compatibility with Existing Integrations

POST /v1/kyc/l2/sessions continues to offer optional hosted verification. New merchant App integrations can submit parameters directly as described here, without first creating a session or using a WebView. The JSON endpoints can only be called after deployment; refer to release notices and endpoint availability in the target environment.