Handle failures
For integration engineers who need a correct response to every way an operation can fail.
Who this is for
Integration engineers building the part of a bank's system that submits token operations and reacts to their outcome. This page covers how to detect a failure, how to tell whether any value moved, and what to do for each failure code.
Two kinds of failure
| Kind | How you see it | Did anything happen? |
|---|---|---|
| Refused at submission | A 4xx response to POST /api/transactions. No operation is created. | No. |
| Failed after acceptance | The operation reaches FAILED. failureCode classifies why; reasonCode gives the specific reason where one was reported. | Establish it from the operation. See the next section. |
A refusal at submission is covered on Errors. The rest of this page is about operations that were accepted and then failed.
Did any value move?
A FAILED operation is terminal. Read two fields to see how far it got:
txHash | blockNumber | What it means |
|---|---|---|
| Absent | Absent | The operation never reached the ledger. No value moved. |
| Present | Present | The ledger transaction was included and reverted. No value moved. reasonCode usually carries the revert reason. |
| Present | Absent | A hash without a block number is not proof of settlement or final rejection. Read the operation and break evidence and reconcile with the operator before submitting a replacement. |
Balances read current contract state. A known pre-broadcast refusal or a verified reverted transaction establishes no token effect. A terminal status or missing hash alone does not settle every broadcast uncertainty; reconcile the ledger and break evidence before reversing cash or issuing a replacement. See Balances.
Recover without repeating a payment
When the response or outcome is uncertain, keep the original instruction and establish what happened before authorising more work. The bank's cash exception and the token outcome need to be reconciled together.
%%{init: {"theme": "neutral"}}%%
flowchart TB
Keep["Preserve the original instruction"] --> Read["Read its current token outcome"]
Read --> Evidence["Establish ledger and break evidence"]
Evidence --> Match["Reconcile cash and token records"]
Match --> Next["Authorise the appropriate next action"]
A pending or unknown outcome remains an investigation. Reuse the original saved key and unchanged body when recovering a lost submission response. A new key represents a new instruction and could create a second payment while the first still settles.
View in API Reference
What to do for each failure code
Replaying a recorded failed operation with its original key returns that operation; it does not restart it. Address the cause and establish the original ledger outcome before authorising a replacement with a new key. The replacement passes through the configured policy, approval and signing path.
failureCode | What happened | What to do |
|---|---|---|
VALIDATION_REJECTED | Validation or policy refused the operation before any ledger transaction was prepared. | Do not resubmit unchanged. Find the rule or check that refused it, and resubmit only if the operation should now pass. |
APPROVAL_REJECTED | An approver refused it. | Treat it as a business decision. A new operation goes through approval again. |
POLICY_EXPIRED | The approval window closed before a decision. | If the payment is still wanted, submit a new operation. Consider why approvers did not act in time. |
POLICY_TIMEOUT | The vocabulary includes a policy-response timeout, but its deadline is not currently enforced. | For an operation still POLICY_PENDING, escalate to the operator. Do not create a replacement merely because time has passed. If a terminal failure is reported, reconcile it before using a new key. |
SIGNING_REJECTED | The custody provider refused to sign. It applies its own policy before signing, independently of the platform. | Check the custody provider's record of the request and its policy. Resubmitting unchanged is likely to be refused again. Escalate through the custody support route agreed for your deployment, with the operation and signing-request identifiers. |
UNPROCESSABLE | Something the operation depends on is missing, such as an active contract or account, or a lock expiry was in the past. | Fix the dependency, then submit a new operation. |
CHAIN_FAILED | The ledger transaction reverted. The API Reference describes this as not worth retrying. | Read reasonCode. Correct the cause (for example an amount above the balance), then submit a new operation. |
RETRY_EXHAUSTED | The platform retried a temporary failure of a system the operation depends on, and ran out of attempts. | Reconcile the terminal operation and break evidence before a new business-authorized instruction. If a hash exists, verify the ledger outcome first; retry exhaustion alone does not prove that a broadcast transaction cannot settle. |
Operations that stop moving
An operation that is not terminal may still be progressing. Do not submit a replacement while the original can still settle: both could confirm.
- Detect it. Alert when an expected completion webhook does not arrive, or when an operation stays in a non-terminal state beyond its expected window. The window is agreed with Quant Network during onboarding.
- Check the breaks queue.
GET /api/transactions/breakslists every operation that failed or stopped moving, newest first, until the case is resolved.reasonCodeis an open set: mostly the failure codes above, plusRECONfor an operation the ledger cannot account for. - A
RECONrow is not a failure yet. The operation was submitted and its ledger transaction has not been found. The ledger is the authority. If the transaction is included, the operation confirms. Ask the operator to establish whether the same prepared transaction can be re-driven safely under the deployed recovery controls. Do not submit a replacement while the case is open.
Investigate and resolve breaks through the operator process agreed for your deployment. The public API reads break evidence but has no endpoint to change its investigation status or resolve it.
Failures and your core banking postings
The platform does not post to your core banking system. Your integration makes both postings.
| Situation | What to do |
|---|---|
MINT fails after you moved the customer's funds to your control account | Hold the cash exception until the original token outcome is established. Reverse the posting or authorise a replacement only after reconciling the failure and any signing/ledger uncertainty. |
BURN fails | No tokens were redeemed. Do not pay out the fiat. Pay out only when the BURN reaches CONFIRMED. |
| An operation confirmed in error | A confirmed operation cannot be rolled back. Submit a compensating operation, for example a BURN for a MINT issued in error, and make the matching posting. |
See Issue and redeem.
Worked example
Read a failed operation:
GET /api/transactions/3f7c1a90-5d2e-4b08-9a41-6c2b8e5d7f13 HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer <access token>
API-Version: 1.0.0HTTP/1.1 200 OK
Content-Type: application/json
{
"transactionId": "3f7c1a90-5d2e-4b08-9a41-6c2b8e5d7f13",
"txType": "MINT",
"assetId": "GBP",
"accountRef": "ACC-0001",
"customerRef": "CUST-0001",
"counterpartyRef": null,
"amount": "10.50",
"params": {},
"state": "FAILED",
"failureCode": "CHAIN_FAILED",
"reasonCode": "EXECUTION_REVERTED",
"txHash": "0x4a1b8c7d2e5f309a6b1c4d7e8f0a2b3c5d6e7f8091a2b3c4d5e6f7089a1b2c3d",
"blockNumber": 18446801,
"createdAt": "2026-08-06T09:29:10.285Z",
"updatedAt": "2026-08-06T09:33:12.550Z"
}txHash and blockNumber are both present, so the ledger transaction was included and reverted. No value moved.
List what stopped moving for the account:
GET /api/transactions/breaks?accountRef=ACC-0001 HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer <access token>
API-Version: 1.0.0HTTP/1.1 200 OK
Content-Type: application/json
{
"content": [
{
"transactionId": "9c4d2f18-73ba-4e6c-8f05-2d17ab903e64",
"reasonCode": "RECON",
"occurredAt": "2026-09-18T09:02:00.000Z",
"txType": "MINT",
"state": "SUBMITTED",
"accountRef": "ACC-0001",
"assetId": "GBP",
"txHash": "0x9f2c1d5e4b8a37c06d1e5f9a2b4c7d8e0f1a2b3c4d5e6f708192a3b4c5d6e7f8",
"breakId": "5e1b7c92-0a34-4d18-b6f7-2c9e4a8d3b51",
"breakStatus": "OPEN",
"detail": {
"reason": "no chain transaction found within the search window",
"nonce": 41
}
},
{
"transactionId": "3f7c1a90-5d2e-4b08-9a41-6c2b8e5d7f13",
"reasonCode": "CHAIN_FAILED",
"occurredAt": "2026-09-18T09:01:00.000Z",
"txType": "BURN",
"state": "FAILED",
"accountRef": "ACC-0001",
"assetId": "GBP",
"txHash": "0x4b81e0c7a2d93f16580ea7c4b39d2f85a61c07be3d49128f0a5c6b2e4d17f903",
"breakId": "c73a2f45-8e1d-4906-a2b8-7f0c5d31e9a4",
"breakStatus": "INVESTIGATING",
"detail": {
"failure": "CONTRACT_REVERTED",
"reasonDetail": "execution reverted: balance below amount",
"attempts": 1
}
}
],
"page": 0,
"size": 20,
"totalElements": 2,
"totalPages": 1
}The first row is a MINT that was submitted and not yet found on the ledger: wait, do not resubmit. The second is a BURN that reverted because the balance was below the amount: correct the amount and submit a new operation with a new key.
View in API Reference
Errors and edge cases
detailhas no fixed schema. Its keys depend on the path that opened the case, and new keys can appear. Read it defensively.- Treasury
occurredAtuses ISO 8601 UTC with three fractional digits, and can be sent back as afromfilter. Thefromandtofilters take ISO 8601. The window is half-open:fromis inclusive,toexclusive. - An unrecognised
reasonfilter returns an empty page, not a400. - A
404on aRELEASEorCANCELnaming a newlockIdis worth retrying. The lock becomes visible shortly after itsLOCKis submitted. - On a
CANCELLEDoperation,failureCodemay hold free text. Do not validate it against the enumeration. - Webhook event types for failures include
transaction.failed,transaction.rejectedandtransaction.cancelled. Treat both failure and rejection notifications as prompts to read the operation. Use its actual state and failure evidence for business decisions, rather than inferring the outcome from the event name.
Follow a Recipe
Step through the code in JavaScript or Python, inspect illustrative responses, and open the connected endpoint schemas.
API Reference
Open an endpoint for request fields, response examples and the interactive API console.
Related pages
Updated 2 days ago

