Cancels¶
POST /cancels¶
Use this to cancel a credit and move the funds to a registered destination. A cancel moves the entire credit — partial cancels are not supported. The credit's asset must match the destination's asset. Destinations must be pre-registered via the address book — inline addresses are not accepted.
Exception: recovery claims use inline destination details on POST /public/recover-funds.
Header:
Idempotency-Key(required)
Parameters¶
| Parameter | Type | Required | Description |
|---|---|---|---|
account_id |
string | Yes | Account to cancel from |
credit_id |
string | Yes | Credit to cancel — the full credit is moved to the destination |
destination_id |
string | Yes | Pre-registered destination for the asset |
client_cancel_id |
string | No | Client-provided cancel identifier for correlation |
Example request:
curl -X POST https://routes.srcry.xyz/v1/cancels \
-H "Authorization: Bearer $ROUTES_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: unique-key-123" \
-d '{
"account_id": "acct_01J...",
"credit_id": "cred_01J...",
"destination_id": "dest_01J...",
"client_cancel_id": "cxl_uniq_123"
}'
import httpx
response = httpx.post(
"https://routes.srcry.xyz/v1/cancels",
headers={
"Authorization": f"Bearer {api_key}",
"Idempotency-Key": "unique-key-123",
},
json={
"account_id": "acct_01J...",
"credit_id": "cred_01J...",
"destination_id": "dest_01J...",
"client_cancel_id": "cxl_uniq_123"
},
)
const response = await fetch("https://routes.srcry.xyz/v1/cancels", {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json",
"Idempotency-Key": "unique-key-123",
},
body: JSON.stringify({
account_id: "acct_01J...",
credit_id: "cred_01J...",
destination_id: "dest_01J...",
client_cancel_id: "cxl_uniq_123"
}),
});
{
"account_id": "acct_01J...",
"credit_id": "cred_01J...",
"destination_id": "dest_01J...",
"client_cancel_id": "cxl_uniq_123"
}
Example response:
{
"request_id": "req_01J...",
"cancel": {
"cancel_id": "cxl_01J...",
"status": "pending",
"credit_id": "cred_01J...",
"client_cancel_id": "cxl_uniq_123",
"poll_after_ms": 10000
}
}
Response fields¶
| Field | Type | Description |
|---|---|---|
request_id |
string | Request identifier |
cancel.cancel_id |
string | Cancel identifier |
cancel.status |
string | Current cancel status |
cancel.credit_id |
string | Credit being cancelled |
cancel.client_cancel_id |
string | Client-provided identifier |
cancel.tx_hash |
string | On-chain transaction hash (present once broadcast) |
cancel.failure_code |
string | Failure reason (terminal only): broadcast_failed, confirmation_timeout |
cancel.poll_after_ms |
integer | Milliseconds until next poll |
GET /cancels/{cancel_id}¶
Use this to poll cancel status. Like trades, non-terminal responses include poll_after_ms.
Non-terminal statuses:
pendingsent
Terminal statuses:
confirmedfailed
The failure_code field indicates the reason. When a cancel fails, the source credit is not consumed — retry with a new cancel request.
broadcast_failed— transaction could not be broadcast to the chain. Retry the cancel.confirmation_timeout— transaction was broadcast but not confirmed within the expected window. Escalate for manual review.
Non-terminal example:
{
"request_id": "req_01J...",
"cancel": {
"cancel_id": "cxl_01J...",
"credit_id": "cred_01J...",
"client_cancel_id": "cxl_uniq_123",
"status": "sent",
"tx_hash": "0xabc123...",
"poll_after_ms": 10000
}
}
Terminal example (confirmed):
{
"request_id": "req_01J...",
"cancel": {
"cancel_id": "cxl_01J...",
"credit_id": "cred_01J...",
"client_cancel_id": "cxl_uniq_123",
"status": "confirmed",
"tx_hash": "0xabc123..."
}
}
Terminal example (failed):
{
"request_id": "req_01J...",
"cancel": {
"cancel_id": "cxl_01J...",
"credit_id": "cred_01J...",
"status": "failed",
"failure_code": "broadcast_failed"
}
}
Cancel lifecycle:
┌──────────┐
│ pending │
└────┬─────┘
│
┌────▼─────┐
│ sent │
└──┬────┬──┘
│ │
┌────▼──────┐ ┌──────────┐
│ confirmed │ │ failed │
└───────────┘ └──────────┘