Operations and their lifecycle
For integration engineers. The token operation types, the states an operation passes through, which states are terminal, and how failures are classified.
Follow an instruction to its outcome
A request to issue, move, redeem or reserve tokens becomes an instruction that your team must track. Quant Flow can accept it before settlement is complete. It may still be waiting for a configured approval, signing or the network outcome.
Operations teams should distinguish submitted, waiting, settled and failed work. Only a confirmed settlement establishes that the token movement completed. A delayed response or missing notification leaves the outcome unresolved; it is not a reason to submit another payment automatically.
Keep one bank-side record for the business instruction and its eventual result. Use that record to reconcile balances, investigate exceptions and avoid duplicate cash postings. The exact operation types, states and failure classifications below support the engineering and support teams.
Operations
An operation is one business instruction against a token: issue, redeem, move, or commit funds. In the API the resource is called a transaction. "Transaction" there means one business operation, which is different from a ledger transaction.
txType | What it does | Fields it carries |
|---|---|---|
MINT | Issues tokens to accountRef. | assetId, accountRef, amount |
BURN | Redeems tokens from accountRef. | assetId, accountRef, amount |
TRANSFER | Moves tokens from accountRef to counterpartyRef. | assetId, accountRef, counterpartyRef, amount |
LOCK | Commits part of accountRef's balance. Two-party if counterpartyRef is named. | assetId, accountRef, amount, optional counterpartyRef, optional params.expiry and params.lockRef |
RELEASE | Completes a lock by paying its destination, or returning the funds if none was named. | params.lockId only |
CANCEL | Completes a lock by returning the funds to the source. Works after the lock has expired. | params.lockId only |
FREEZE, UNFREEZE | Change account controls without moving value. | Submit through POST /api/accounts/{accountRef}/controls, not POST /api/transactions. operation is FREEZE or UNFREEZE; reason is required for a freeze and optional for an unfreeze, up to 100 characters. |
DEPLOY | Deploys and registers an asset's token contract. | Submit through POST /api/contracts, not POST /api/transactions. |
Locks, releases and cancellations are covered in Transfers, locks and releases.
Map the operation to your application's status
Store one durable record per business instruction and update it as the platform reports progress. Use the returned transactionId for reads and retain txHash when it appears; they identify different things. One is the platform operation, the other is its settling ledger transaction.
| Platform fact | Suitable application behaviour |
|---|---|
Submission returned 202 | Show submitted or processing; retain the identifier. |
| Operation awaits approval | Show awaiting sign-off and link to the related approval workflow. |
| Signed or submitted to the network | Keep processing; neither proves settlement. |
CONFIRMED | Mark the token operation settled and perform the workflow's bank-side booking or reconciliation step. |
FAILED or CANCELLED | Retain the reason and apply the flow-specific recovery procedure. |
| No definitive outcome | Show an unresolved instruction and investigate; a client deadline does not change platform state. |
Keep customer-facing messages understandable, while retaining the exact state and failure codes for support. Process repeated reads and events idempotently so a confirmed operation does not cause a second cash posting.
The lifecycle
Submission is asynchronous. POST /api/transactions returns 202 when the request is well formed and the accounts it names are usable. The operation then moves through the configured policy and settlement path. Policy is disabled in the shipped configuration: an operation starts in BATCHED when policy is disabled or its type is excluded. When enabled for the type, it starts in POLICY_PENDING. You find out where it got to by reading it back, or from webhooks.
stateDiagram-v2
[*] --> POLICY_PENDING: 202, policy enabled for this type
[*] --> BATCHED: 202, policy disabled or type excluded
POLICY_PENDING --> VALIDATED: COMPLETED
POLICY_PENDING --> AWAITING_APPROVAL: PENDING
POLICY_PENDING --> FAILED: REJECTED or EXPIRED
POLICY_PENDING --> CANCELLED: CANCELLED
AWAITING_APPROVAL --> VALIDATED: COMPLETED
AWAITING_APPROVAL --> FAILED: REJECTED or EXPIRED
AWAITING_APPROVAL --> CANCELLED: CANCELLED
VALIDATED --> HELD: Insufficient balance gate
VALIDATED --> BATCHED
BATCHED --> PREPARED
PREPARED --> SIGNED
PREPARED --> AWAITING_APPROVAL: Custody approval pending
SIGNED --> SUBMITTED
SUBMITTED --> CONFIRMED
PREPARED --> FAILED
SUBMITTED --> FAILED
CONFIRMED --> [*]
FAILED --> [*]
CANCELLED --> [*]
The same model as a table:
| State | Stage | Meaning | Terminal |
|---|---|---|---|
POLICY_PENDING | Policy | Awaiting a policy decision. | No |
VALIDATED | Policy outcome | Cleared by policy. | No |
HELD | Policy outcome | Parked at the insufficient-balance gate; this is different from waiting for an approver. | No |
AWAITING_APPROVAL | Policy outcome | Waiting for an approver. | No |
BATCHED | Settlement | Settlement in progress. | No |
PREPARED | Settlement | Settlement in progress. | No |
SIGNED | Settlement | Settlement in progress. | No |
SUBMITTED | Settlement | Sent to the ledger. txHash is present; blockNumber is not yet. | No |
CONFIRMED | Outcome | Settled. Balances now reflect it. | Yes |
FAILED | Outcome | Ended badly. failureCode says why. | Yes |
CANCELLED | Outcome | Withdrawn. | Yes |
RECEIVED | Retired | No longer used. Operations submitted before it was retired may still report it. | No |
CONFIRMED, FAILED and CANCELLED are terminal. They will not change again. Every other state may have moved on since you read it.
The diagram shows the documented policy and settlement paths, not every internal retry transition. When policy is enabled, the shipped judged types are MINT, BURN, TRANSFER and LOCK; RELEASE and CANCEL are excluded. The environment's configuration can change this set. A policy CANCELLED decision cancels the operation; cancellation while awaiting approval also cancels its lock.
Do not rely on an automatic policy timeout. The configured response deadline is not currently enforced. An unanswered operation can remain POLICY_PENDING until an operator acts; alert and investigate rather than submitting another operation. Approval-request expiry is a separate policy-engine mechanism.
- Use the states returned by transaction reads rather than assuming that every intermediate state will be observed. Out-of-order pipeline events can advance the reported state; only the documented terminal states establish the final platform outcome.
- Confirm the caller's account-control and cancellation entitlements before exposing these actions in your application.
Reading progress
GET /api/transactions/{transactionId} returns the operation as it stood at the moment of the read, dated by updatedAt.
| Field | Present when |
|---|---|
failureCode | The operation ended badly. Absent, not null, while in flight and when confirmed. |
reasonCode | A more specific reason was reported, such as a revert reason. Absent otherwise. |
txHash | The operation has been submitted for settlement. Absent permanently if it failed before then. |
blockNumber | The ledger transaction has been mined. |
txHash without blockNumber means in flight on the ledger. Both present means settled or reverted: read state to tell which.
On a CANCELLED operation, failureCode may carry a free-text reason instead of a code. Do not validate it against the enumeration in that case.
Webhook event types include transaction.confirmed, transaction.failed, transaction.rejected, transaction.cancelled and transaction.awaiting_approval. Treat events as notifications and read the operation for its authoritative state and failure details. Do not derive a terminal state from transaction.rejected alone. See Webhooks.
Failure codes
failureCode | Meaning (from the API Reference) |
|---|---|
VALIDATION_REJECTED | Validation, screening or policy refused it. |
APPROVAL_REJECTED | An approver refused it. |
SIGNING_REJECTED | Signing refused it. |
CHAIN_FAILED | Settlement failed in a way not worth retrying. |
RETRY_EXHAUSTED | The attempt budget ran out. |
UNPROCESSABLE | Something the operation depends on is missing, such as an active contract or account. Also the result of a lock expiry in the past or not a valid instant. |
POLICY_EXPIRED | The policy decision was not made in time. |
POLICY_TIMEOUT | No policy decision arrived within the time allowed. |
A failed signing or broadcast can be redispatched up to the configured maximum of five chain-transaction attempts by default. Retry eligibility depends on configured reason-code lists. RETRY_EXHAUSTED means this budget ran out. Confirm your environment's settings with Quant Network; do not assume a per-organisation setting.
When an operation is interrupted
A timeout, restart or server error leaves the outcome uncertain until you recover evidence. Keep the original request body, idempotency key and any returned transaction ID. Idempotency replays a recorded operation; it does not establish that every failure across storage, messaging, signing and the ledger was rolled back.
Progression is event-driven. The service documentation states that there is no general sweep or automatic re-drive for a lost operation announcement. An operation that stops progressing can require operator intervention. Do not create a replacement simply because it has waited too long.
| Observation | What it establishes | Recovery |
|---|---|---|
No response or a submission 5xx | Acceptance and downstream progress are unknown. | Recover using the original key and unchanged body within a bounded retry budget. Read the returned operation and investigate unresolved evidence with the operator. |
| Recorded operation, no later progress | The operation exists; a stalled notification is not proof of rejection. | Read its state and the breaks queue. Ask the operator to diagnose and recover stalled work. |
| Signing requested, no answer | Custody may still be processing the request. | Retain signing/operation evidence and coordinate with the custody owner. Do not create another payment intent. |
| Ledger submission without confirmation | The transaction may still be included. | Reconcile the hash/nonce and ledger result with the operator; do not submit a replacement. |
CONFIRMED, webhook missing | The API reports completed settlement. | Read the operation and recover the delivery through the webhook history/redelivery API. |
A signed ledger transaction has fixed content and a nonce. Re-sending that same signed transaction differs from creating a new operation with a new key. Bank cash postings are a separate record and must be reconciled with the established token outcome.
A confirmed operation cannot be rolled back. A correction is a separately authorised compensating instruction, with its own business justification and controls. Establish the original outcome before deciding whether one is needed.
What a client can retry
| Case | Retry? |
|---|---|
Network failure or 5xx on submission | Recover with the same key and unchanged body, using bounded retries. A recorded-operation replay returns its current state with 200; unresolved server errors still require investigation. |
404 on a RELEASE or CANCEL naming a lockId | Yes. The lock becomes visible shortly after its LOCK is submitted. This is the one refusal on submission worth retrying. |
Any other 4xx on submission | No. Correct the request. |
An operation that ended FAILED | Not by resubmitting the same key: that returns the failed operation. Establish the cause and reconcile any signing or ledger uncertainty before authorising a new instruction with a new key. Handle failures gives the action for each failureCode. |
On this endpoint, reusing a key with a different payload does not return 422. It returns the first operation and ignores the new payload. Other write endpoints return 422 in that case. Generate a new key for every new instruction.
Keep a durable instruction journal
Your bank adapter owns the correlation between a business instruction, its original request/key and Quant Flow's operation ID. Update its last observed state and observation time from events and reads without discarding the original intent. Preserve ledger evidence when available; transactionId and txHash identify different layers.
A customer-facing status should distinguish accepted/pending, confirmed and failed. Route unclear outcomes to an investigation state in your application rather than inventing a platform state or submitting another instruction. Quant Flow supplies operation/break reads; the bank owns the investigation queue and cash reconciliation, with operator diagnosis where needed. See Daily operations and monitoring.
Worked example
Read an operation that has settled.
GET /api/transactions/9c4d2f18-73ba-4e6c-8f05-2d17ab903e64 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": "9c4d2f18-73ba-4e6c-8f05-2d17ab903e64",
"txType": "LOCK",
"assetId": "GBP",
"accountRef": "ACC-0001",
"customerRef": "CUST-0001",
"counterpartyRef": "ACC-0002",
"amount": "100.00",
"params": {
"expiry": "2027-01-01T00:00:00Z",
"lockRef": "INV-88421",
"lockId": "b28f1a4c-9d3e-4f27-8a56-1e0c7b9d42a1",
"chainLockId": "0x00000000000000000000000000000000b28f1a4c9d3e4f278a561e0c7b9d42a1",
"destination": "0x8B1cA3D5e07F2b94aC61d8E30f5A7b249C0e6D18"
},
"state": "CONFIRMED",
"txHash": "0x9f2c1d5e4b8a37c06d1e5f9a2b4c7d8e0f1a2b3c4d5e6f708192a3b4c5d6e7f8",
"blockNumber": 18446744,
"createdAt": "2026-08-06T09:29:10.285Z",
"updatedAt": "2026-08-06T09:31:47.902Z"
}An operation still in flight has no txHash, blockNumber or reasonCode:
{
"transactionId": "7d1e4c93-2a68-4f51-b0c7-3e95a4d81f26",
"txType": "MINT",
"assetId": "GBP",
"accountRef": "ACC-0001",
"customerRef": "CUST-0001",
"counterpartyRef": null,
"amount": "10.50",
"params": {},
"state": "VALIDATED",
"createdAt": "2026-08-06T09:29:10.285Z",
"updatedAt": "2026-08-06T09:29:12.041Z"
}View in API Reference
- Get one token operation ·
GET
Errors and edge cases
| Situation | Response |
|---|---|
transactionId is not a UUID | 400 |
| No such operation in your organisation | 404 |
state or txType filter names a value that does not exist | 400 on the list endpoint |
size outside 1 to 100 | 400. The value is rejected, not clamped. |
The operation log (GET /api/transactions) is ordered newest first, with transactionId as a tiebreaker. Account and customer listings are oldest first. The accountRef filter matches operations originating from that account only; an operation naming it as the counterparty is not matched. The log has no date-range filter.
Use webhooks as the primary signal and polling as the fallback. Alert when an expected completion event 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. Use a bounded poll interval with backoff and jitter chosen for your environment. After a local deadline, keep the instruction unresolved and alert the operator rather than submitting a replacement.
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
- Balances
- Policy, approvals and audit
- Transfers, locks and releases
- Handle failures
- Idempotency and retries
- Webhooks
Implementation resources
Use Implement a backend client for request handling, durable idempotency and outcome tracking. The developer integration coverage map links every public operation to its API Reference and contract-derived code recipe. Replace example identifiers with values from your assigned environment.
Updated 2 days ago

