Z Zise Developers 简体中文

Cancel: only needs_reconfirm is cancellable

POST /v1/remittances/{id}/cancel scope: remittances:write
On behalf of a member · x-on-behalf-of required Requires x-idempotency-key Moves funds · Release the member’s locked funds, including additional holds from every earlier round, back to available balance and simultaneously release your prepaid hold
This endpoint moves funds

See the response table below for failure handling. Retry timeouts (504) with the same idempotency key — we may already have processed the request; use a new key after a business failure; the same key replays that failure.

There is only one cancellation window: needs_reconfirm. Execution cost exceeded the user’s slippage ceiling, so we stopped to ask whether they will pay more. If they decline, funds return to available balance and limit reservations are released.

Other states cannot be cancelled, for two reasons:

  • reviewing / dispatching / submitting / processing: the payout may already have reached the upstream, which has no cancellation endpoint. submitting is especially sensitive: the request was sent but its outcome is unknown, and manual overrides are rejected.
  • Terminal states, completed / failed / canceled / refunded: already finished.

Requests to cancel these categories require support and our administrative review, a manual process.

A state that disallows cancellation returns 400 state_invalid. ⚠ Do not use that code alone to infer cancellability. Claiming can fail for four reasons: concurrent status changes, an existing settlement journal, no locking journal, or a state outside the cancellable set. state_invalid does not distinguish them. Use GET /v1/remittances/{id}/pending-action: a non-null action indicates the cancellation window.

Prerequisites

  • Order belongs to this member and merchant
  • Order status is needs_reconfirm

Path Parameters

FieldTypeRequiredDescription
id string Required Order ID, with or without the rmt_ prefix.
FieldTypeRequiredDescription
x-on-behalf-of string Required Member on whose behalf the call is made.
x-idempotency-key string Required UUID v4。

Request Body

No fields. Send an empty object {}; write requests require signing, covering these exact bytes.

Response

200Cancelled; funds returned to available balance
{
  "id": "rmt_9c1f0a7e-3b2d-4f81-9a55-1d2e3f4a5b6c",
  "status": "canceled"
}
404not_found: order not associated with this member or not owned by you. Both produce the same response, avoiding an order-ID discovery oracle.
500⚠ Current implementation: an order outside needs_reconfirm falls here as api_error. Retrying will not resolve it; see the warning above.
Request
curl -X POST 'https://api.zinfra.vip/v1/remittances/{id}/cancel' \
  -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 '{}'
const res = await fetch("https://api.zinfra.vip/v1/remittances/{id}/cancel", {
  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({}),
});
// Keep monetary amounts as strings, never numbers.
const data = await res.json();
import requests

res = requests.post(
    "https://api.zinfra.vip/v1/remittances/{id}/cancel",
    headers={
        "x-auth-token": "Bearer $TOKEN",
        "x-on-behalf-of": "$MEMBER_ID",
        "x-idempotency-key": "$IDEMPOTENCY_KEY",
        "content-type": "application/json",
    },
    json={},
)
# Use Decimal(str(...)) for amounts, not float.
data = res.json()
req, _ := http.NewRequest("POST", "https://api.zinfra.vip/v1/remittances/{id}/cancel",
    strings.NewReader(`{}`))
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/remittances/{id}/cancel"))
    .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("""
{}
"""))
    .build();
// Use String / BigDecimal for amounts, not double.
$ch = curl_init('https://api.zinfra.vip/v1/remittances/{id}/cancel');
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'
{}
JSON,
]);
$res = curl_exec($ch);
// Use bcmath / strings for amounts, not floatval.
200
{
  "id": "rmt_9c1f0a7e-3b2d-4f81-9a55-1d2e3f4a5b6c",
  "status": "canceled"
}