Z Zise Developers 简体中文

Application status

GET /v1/cards/applications/{id} scope: cards:read
On behalf of a member · x-on-behalf-of required

⚠ status here is the original internal value, not the three reduced values from POST. You can see pending_merchant_funds (your prepaid balance is insufficient), pending_review (awaiting our manual review), and allocating / picking / shipped / awaiting_bind / binding / pending_activation (the six physical card fulfillment states). Do not make the default branch fall back to processing: display the original value to your operations team. We will record unfamiliar values in the changelog.

The actual terminal state for physical card applications is pending_activation: the cards row already exists and no process advances the application further. Do not wait for an issued state that will never arrive.

card_id identifies the card ultimately associated with this application. It is null until a card exists; once populated, use it directly with GET /v1/cards/{id}. Do not guess which card belongs to the application from the card list.

Channels supporting cardholder status synchronization also return cardholder_review_status: approved / pending / rejected, or null when no cardholder is associated. approved means only that cardholder review passed, not that the card was issued or shipped. The card.application.submitted notification may also include this field. On receipt, query the application details and continue according to the application's own status; do not resubmit KYC or the card application. When the physical card reaches the user, a separate card.application.awaiting_bind event is sent; query the application and proceed with binding and activation. An approved standard application using downstream inventory automatically enters awaiting_bind; there is no need to wait for shipment from our administration system.

Path Parameters

FieldTypeRequiredDescription
id string Required Application ID. Accepted with or without the cap_ prefix.
FieldTypeRequiredDescription
x-on-behalf-of string Required The member on whose behalf to call. Must own this application; otherwise returns 404.

Response

200OK
{
  "id": "cap_1b7d90c4-5e2a-4f18-83b6-0c7a4d1e9f22",
  "status": "pending_activation",
  "form_factor": "physical",
  "card_id": "crd_2c9e4b10-77af-4d3a-8e51-b0d6c2f9a134",
  "failure_code": "",
  "supplement": null,
  "created_at": "2026-08-01T02:11:43.000Z"
}
404not_found: the application does not exist or does not belong to this member/merchant.

Additional Details

supplement: null when there is no outstanding case; the field is not omitted

When the application enters need_docs, this becomes an object:

  • status: pending (waiting for the member's documents; remind them) / submitted (submitted and awaiting upstream review; reminders will not help).
  • required_items: cert_front / cert_back / address / name / birth / cert_id / other. **An unrecognized upstream reason falls back to ["other"], never an empty array**: a Documents required screen with no listed items gives the user no way to know what to submit.
  • deadline: the deadline on this business line is enforced, unlike remittance supplements, which deliberately use null. On expiry, the application becomes failed and the issuance fee is refunded. An empty string means no deadline was set on historical data.
  • submit_via: always POST /v1/cards/applications/{id}/supplement-sessions, not a ready-to-use URL. Hosted-screen links are single-use, bound to the member and case, and valid for 24 hours. Embedding one in details would effectively make it a permanent link: details are read repeatedly, logged, and forwarded, while the URL can submit documents as that member. Request a fresh hosted_url when documents need to be submitted.

Emitted Events

Green = successful terminal state · Red = terminal state requiring action · Purple = intermediate state. Open an event for its payload and signature verification details.

Request
curl -X GET 'https://api.zinfra.vip/v1/cards/applications/{id}' \
  -H 'x-auth-token: Bearer $TOKEN' \
  -H 'x-on-behalf-of: $MEMBER_ID'
const res = await fetch("https://api.zinfra.vip/v1/cards/applications/{id}", {
  method: "GET",
  headers: {
    "x-auth-token": "Bearer $TOKEN",
    "x-on-behalf-of": "$MEMBER_ID",
  },
});
// Keep monetary amounts as strings, never numbers.
const data = await res.json();
import requests

res = requests.get(
    "https://api.zinfra.vip/v1/cards/applications/{id}",
    headers={
        "x-auth-token": "Bearer $TOKEN",
        "x-on-behalf-of": "$MEMBER_ID",
    },
)
# Use Decimal(str(...)) for amounts, not float.
data = res.json()
req, _ := http.NewRequest("GET", "https://api.zinfra.vip/v1/cards/applications/{id}",
    nil)
req.Header.Set("x-auth-token", "Bearer $TOKEN")
req.Header.Set("x-on-behalf-of", "$MEMBER_ID")
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/cards/applications/{id}"))
    .header("x-auth-token", "Bearer $TOKEN")
    .header("x-on-behalf-of", "$MEMBER_ID")
    .method("GET", HttpRequest.BodyPublishers.noBody())
    .build();
// Use String / BigDecimal for amounts, not double.
$ch = curl_init('https://api.zinfra.vip/v1/cards/applications/{id}');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'GET',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'x-auth-token: Bearer $TOKEN',
    'x-on-behalf-of: $MEMBER_ID',
  ],
]);
$res = curl_exec($ch);
// Use bcmath / strings for amounts, not floatval.
200
{
  "id": "cap_1b7d90c4-5e2a-4f18-83b6-0c7a4d1e9f22",
  "status": "pending_activation",
  "form_factor": "physical",
  "card_id": "crd_2c9e4b10-77af-4d3a-8e51-b0d6c2f9a134",
  "failure_code": "",
  "supplement": null,
  "created_at": "2026-08-01T02:11:43.000Z"
}