Cancel: only needs_reconfirm is cancellable
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
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.submittingis 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
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | Required | Order ID, with or without the rmt_ prefix. |
Request Headers
| Field | Type | Required | Description |
|---|---|---|---|
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
{
"id": "rmt_9c1f0a7e-3b2d-4f81-9a55-1d2e3f4a5b6c",
"status": "canceled"
}not_found: order not associated with this member or not owned by you. Both produce the same response, avoiding an order-ID discovery oracle.needs_reconfirm falls here as api_error. Retrying will not resolve it; see the warning above.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.
{
"id": "rmt_9c1f0a7e-3b2d-4f81-9a55-1d2e3f4a5b6c",
"status": "canceled"
}