Exclusively bind a quick KYC profile to a member
x-on-behalf-of required
Requires x-idempotency-key
Called on behalf of a member. An existing matching binding is reused with 200 and no charge. Otherwise, a profile is claimed from the pool with a one-time profile fee, default 10 USDT. Platform members pay from their own balance; downstream merchants pay from prepayment, with merchant cost determined by configured rates. Each member may have at most 5 bindings. A new allocation requires email; the complete email address must never have been used in standard KYC, the quick-profile pool, or historical profiles. Email comparison ignores case and surrounding whitespace; Gmail +别名 is preserved. Reusing an existing binding does not require a new email.
Supply card_product_id to match the card product's country/document requirements, or supply only country + identity_type.
L0 members may bind without first completing their own L1. Members with genuine L1 / L2 approval may also bind. Quick profiles apply only to eligible card products; they do not replace the member's own identity profile or change their existing KYC level, and cannot substitute for personal remittance or L2 requirements. Both newly allocated and reused bindings return binding.identity_issue_country as the bound profile's document-issuing country, a two-letter code or an empty string for historical profiles without it, consistent with the bound-profile list. After explicitly binding, pass the returned binding.id as quick_kyc_binding_id to both GET /v1/cards/products/{id}/quote and POST /v1/cards/applications. Both requests must be on behalf of the same member. Quick binding cannot bypass an L2 requirement on a card product. Without genuine L1, POST /v1/cards/applications automatically uses the same reuse/allocation process; a new allocation requires quick_kyc_email. Pending standard KYC does not switch automatically; explicitly choose quick KYC with quick_kyc_binding_id.
Request Headers
| Field | Type | Required | Description |
|---|---|---|---|
x-idempotency-key |
string | Required | |
x-on-behalf-of |
string | Required |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
email |
string | Optional | Required for a new allocation: a complete email address never used for any KYC. |
card_product_id |
string | Optional | |
country |
string | Optional | |
identity_type |
string | Optional |
Response
{
"reused": true,
"remaining": 4,
"binding": {
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"identity_type": "passport",
"identity_issue_country": "HK",
"nationality": "HK",
"address_country": "HK",
"created_at": "2026-09-05T06:12:00.000Z"
}
}{
"reused": false,
"remaining": 4,
"binding": {
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"identity_type": "passport",
"identity_issue_country": "HK",
"nationality": "HK",
"address_country": "HK",
"created_at": "2026-09-05T06:12:00.000Z"
}
}quick_kyc_disabled · quick_kyc_limit · quick_kyc_exhausted · quick_kyc_unpaid · invalid_request · member_context_requiredmember_not_foundidempotency_key_reused · idempotency_in_progresscurl -X POST 'https://api.zinfra.vip/v1/kyc/quick' \
-H 'x-auth-token: Bearer $TOKEN' \
-H 'x-on-behalf-of: $MEMBER_ID' \
-H 'x-idempotency-key: $IDEMPOTENCY_KEY' \
-H 'content-type: application/json' \
-d '{
"card_product_id": "cpd_visa_virtual_usd",
"email": "member+quick@example.com"
}'const res = await fetch("https://api.zinfra.vip/v1/kyc/quick", {
method: "POST",
headers: {
"x-auth-token": "Bearer $TOKEN",
"x-on-behalf-of": "$MEMBER_ID",
"x-idempotency-key": "$IDEMPOTENCY_KEY",
"content-type": "application/json",
},
body: JSON.stringify({
"card_product_id": "cpd_visa_virtual_usd",
"email": "member+quick@example.com"
}),
});
// Keep monetary amounts as strings, never numbers.
const data = await res.json();import requests
res = requests.post(
"https://api.zinfra.vip/v1/kyc/quick",
headers={
"x-auth-token": "Bearer $TOKEN",
"x-on-behalf-of": "$MEMBER_ID",
"x-idempotency-key": "$IDEMPOTENCY_KEY",
"content-type": "application/json",
},
json={
"card_product_id": "cpd_visa_virtual_usd",
"email": "member+quick@example.com"
},
)
# Use Decimal(str(...)) for amounts, not float.
data = res.json()req, _ := http.NewRequest("POST", "https://api.zinfra.vip/v1/kyc/quick",
strings.NewReader(`{
"card_product_id": "cpd_visa_virtual_usd",
"email": "member+quick@example.com"
}`))
req.Header.Set("x-auth-token", "Bearer $TOKEN")
req.Header.Set("x-on-behalf-of", "$MEMBER_ID")
req.Header.Set("x-idempotency-key", "$IDEMPOTENCY_KEY")
req.Header.Set("content-type", "application/json")
res, err := http.DefaultClient.Do(req)
// Decode amount fields as string, not float64.HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.zinfra.vip/v1/kyc/quick"))
.header("x-auth-token", "Bearer $TOKEN")
.header("x-on-behalf-of", "$MEMBER_ID")
.header("x-idempotency-key", "$IDEMPOTENCY_KEY")
.header("content-type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("""
{
"card_product_id": "cpd_visa_virtual_usd",
"email": "member+quick@example.com"
}
"""))
.build();
// Use String / BigDecimal for amounts, not double.$ch = curl_init('https://api.zinfra.vip/v1/kyc/quick');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'x-auth-token: Bearer $TOKEN',
'x-on-behalf-of: $MEMBER_ID',
'x-idempotency-key: $IDEMPOTENCY_KEY',
'content-type: application/json',
],
CURLOPT_POSTFIELDS => <<<'JSON'
{
"card_product_id": "cpd_visa_virtual_usd",
"email": "member+quick@example.com"
}
JSON,
]);
$res = curl_exec($ch);
// Use bcmath / strings for amounts, not floatval.
{
"reused": true,
"remaining": 4,
"binding": {
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"identity_type": "passport",
"identity_issue_country": "HK",
"nationality": "HK",
"address_country": "HK",
"created_at": "2026-09-05T06:12:00.000Z"
}
}