Z Zise Developers 简体中文

Card closure precheck

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

Card closure is irreversible. POST /v1/cards/{id}/close automatically returns the entire remaining card balance, ignoring the product's minimum retained balance, then freezes and closes the card after credit is confirmed. Regular POST /v1/cards/{id}/withdrawals remains subject to the minimum retained balance and does not accept reason=close.

Use the precheck to decide whether to close the card and to track the stage after requesting closure: closePhase: idle: you may submit close. sweeping / freezing / closing: already in progress; poll this endpoint. blocked_hold: unsettled authorizations exist; wait for settlement. blocked_fee: outstanding card transaction fees exist.

⚠ canClose: false no longer means you should call withdrawals yourself first. When the remaining balance is below the minimum retained amount, canClose is still false; submit POST close directly. pendingWithdraw: true or closePhase: sweeping means the balance return is in progress; do not initiate another one.

⚠ This endpoint uses camelCase field names (canClose / pendingWithdraw / closePhase), unlike the snake_case used elsewhere. This is a legacy inconsistency; parse them as camelCase.

Path Parameters

FieldTypeRequiredDescription
id string Required Card ID
FieldTypeRequiredDescription
x-on-behalf-of string Required The member on whose behalf to call.

Response

200All amounts are integer strings in the smallest unit; convert using scale in the same response. held = balance − withdrawable and may include administrative freezes. Only authHeld represents unsettled authorizations; use that column for the closure button.
{
  "balance": "8000000",
  "held": "0",
  "authHeld": "0",
  "withdrawable": "8000000",
  "canClose": false,
  "pendingWithdraw": false,
  "closeRequested": false,
  "closePhase": "idle",
  "scale": 6,
  "currency": "USD"
}
404not_found: the card does not exist or does not belong to this member.
Request
curl -X GET 'https://api.zinfra.vip/v1/cards/{id}/close-check' \
  -H 'x-auth-token: Bearer $TOKEN' \
  -H 'x-on-behalf-of: $MEMBER_ID'
const res = await fetch("https://api.zinfra.vip/v1/cards/{id}/close-check", {
  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/{id}/close-check",
    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/{id}/close-check",
    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/{id}/close-check"))
    .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/{id}/close-check');
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
{
  "balance": "8000000",
  "held": "0",
  "authHeld": "0",
  "withdrawable": "8000000",
  "canClose": false,
  "pendingWithdraw": false,
  "closeRequested": false,
  "closePhase": "idle",
  "scale": 6,
  "currency": "USD"
}