Z Zise Developers 简体中文

Close a card (irreversible; we return the remaining balance)

POST /v1/cards/{id}/close scope: cards:write
On behalf of a member · x-on-behalf-of required Requires x-idempotency-key

Irreversible. Once accepted, the sequence is: return the entire remaining card balance to available balance, ignoring the product's minimum retained balance → wait for credit → freeze → close with the upstream. Authorized but unsettled transactions and outstanding card transaction fees still cause rejection; ask the user to wait for settlement.

The returned status is the card's current status and may still be active while the balance return is in progress. closePhase identifies the orchestration stage. Calling again on a card already closed / expired / replaced / closing returns 200 directly, idempotently.

⚠ A closed card cannot be reopened. Members who need a card must complete issuance again. Replacement is a separate process; see POST /v1/cards/{id}/replacements.

Prerequisites

  • No authorized but unsettled transactions exist.
  • No outstanding card transaction fees exist.

Path Parameters

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

Request Body

FieldTypeRequiredDescription
reason string Optional Closure reason, recorded in our audit trail and truncated to 200 characters. Does not affect eligibility.

Response

200Accepted, or the card was already in a terminal state; both cases return the same response.
{
  "id": "crd_9f2c1b7a-3d51-4a2e-9c08-6b1f0d4e77aa",
  "status": "active",
  "closePhase": "sweeping"
}
400state_invalid: unsettled authorizations, outstanding fees, or upstream rejection of closure. product_not_available: issuer unavailable. idempotency_key_required / idempotency_key_invalid.
404not_found: the card does not exist or does not belong to this member.

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 POST 'https://api.zinfra.vip/v1/cards/{id}/close' \
  -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 '{
    "reason": "用户不再需要"
  }'
const res = await fetch("https://api.zinfra.vip/v1/cards/{id}/close", {
  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({
    "reason": "用户不再需要"
  }),
});
// Keep monetary amounts as strings, never numbers.
const data = await res.json();
import requests

res = requests.post(
    "https://api.zinfra.vip/v1/cards/{id}/close",
    headers={
        "x-auth-token": "Bearer $TOKEN",
        "x-on-behalf-of": "$MEMBER_ID",
        "x-idempotency-key": "$IDEMPOTENCY_KEY",
        "content-type": "application/json",
    },
    json={
      "reason": "用户不再需要"
    },
)
# Use Decimal(str(...)) for amounts, not float.
data = res.json()
req, _ := http.NewRequest("POST", "https://api.zinfra.vip/v1/cards/{id}/close",
    strings.NewReader(`{
  "reason": "用户不再需要"
}`))
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/cards/{id}/close"))
    .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("""
{
  "reason": "用户不再需要"
}
"""))
    .build();
// Use String / BigDecimal for amounts, not double.
$ch = curl_init('https://api.zinfra.vip/v1/cards/{id}/close');
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'
{
  "reason": "用户不再需要"
}
JSON,
]);
$res = curl_exec($ch);
// Use bcmath / strings for amounts, not floatval.
200
{
  "id": "crd_9f2c1b7a-3d51-4a2e-9c08-6b1f0d4e77aa",
  "status": "active",
  "closePhase": "sweeping"
}