Transfers, locks and releases

For integration engineers who move tokens between accounts, or commit funds with a lock and complete it later.

Use transfers to move tokens between accounts, and locks to reserve funds for a later release or cancellation. All four instructions use the transaction endpoint, but their body shapes and effects differ. Track each to confirmation and retain both the transaction ID and any lock ID.

Choose a transfer or a lock

A transfer is an immediate instruction to pay another token account once settlement succeeds. A lock earmarks an amount while a business condition is outstanding. For an invoice, your system might create a two-party lock naming the supplier's account, then release it after receipt is verified or cancel it if the order falls through. Quant Flow does not verify delivery of the goods; your application decides when that condition is met.

A one-party lock holds funds without naming a beneficiary. Releasing or cancelling it returns spending availability to the same account. Choose the shape before submitting: you cannot add or replace a lock's destination later.

Do not treat CANCEL as a general transaction-cancellation command. Here it completes an existing lock. A confirmed transfer cannot be undone by submitting CANCEL; any corrective movement is a new, authorised business instruction.

Operation behavior

  • All four operations use POST /api/transactions.
  • TRANSFER moves tokens from accountRef to counterpartyRef, and is the one type that requires a counterparty. Both fields name accounts, never customers.
  • A LOCK is one-party or two-party, decided by counterpartyRef alone. If named, releasing the lock pays that account. If absent, the funds can only return to accountRef. This is fixed when the lock is created.
  • A LOCK accepts params.expiry (an ISO 8601 instant in the future; omit it for a lock that never expires) and params.lockRef (the bank's own payment reference). A past or invalid expiry is accepted with 202 and later ends FAILED with UNPROCESSABLE.
  • The lockId is assigned by the platform and returned in params on the 202 response. GET /api/transactions/{transactionId} also returns it. A caller cannot choose it.
  • A RELEASE or CANCEL carries txType and params.lockId only. Supplying assetId, accountRef or amount is a 400.
  • A release pays the lock's destination, or returns the funds if none was named. A cancellation always returns the funds to the source, and still works after the lock has expired. An expired lock can only be unwound by a cancel, so its funds stay locked until you submit a CANCEL.
  • Every transfer, lock, release and cancel settles only on CONFIRMED. Policy runs only when enabled for the type: the shipped judged set includes TRANSFER and LOCK, but excludes RELEASE and CANCEL. Signing can still require custody approval. Recover an interrupted submission with the same key and unchanged body; a recorded key replays the existing operation. Investigate unresolved server or ledger outcomes rather than generating a replacement key. See Operations and their lifecycle.
  • The lock must exist and be ACTIVE. A second completion while one is in flight is a 400. An unknown lock is a 404, which the spec says is worth retrying.
  • Balances show total, available and locked: GET /api/accounts/{accountRef}/balances.

Complete a confirmed lock

%%{init: {"theme": "neutral"}}%%
flowchart TB
    Submit["Submit LOCK / store transactionId and lockId"] --> Confirm["Wait for LOCK operation CONFIRMED"]
    Confirm --> Active["Funds locked on-chain"]
    Active --> Release["RELEASE before expiry"]
    Active --> Cancel["CANCEL / including after expiry"]
    Release --> R["CONFIRMED / pay fixed destination or return to source"]
    Cancel --> C["CONFIRMED / return funds to source"]

Release and cancel are alternative instructions, each with its own idempotency key. Expiry alone does not free funds. Investigate a failed completion before retrying or replacing it.

Submit LOCK, RELEASE or CANCEL · Read operation · Read balance

Create and complete a lock

  1. Read the account's balance and reconcile outstanding operations. A balance read does not reserve funds.
  2. Submit LOCK with a new Idempotency-Key. Persist both transactionId and params.lockId before continuing.
  3. Read the operation until CONFIRMED, or process its outcome webhook. Acceptance alone does not prove the funds are locked on-chain.
  4. To pay the fixed destination, submit RELEASE before expiry. To return the funds to the source, submit CANCEL; cancellation also works after expiry. Each completion is a new instruction with its own key.
  5. Track the completion to CONFIRMED, then reconcile the balances and your cash/bookkeeping leg. A failed on-chain completion leaves the lock active; investigate before another attempt.

Expiry does not release or cancel funds by itself. There is no automatic EXPIRED lock transition: a cancel is required to unwind an expired lock. Do not run both completion examples against the same lock.

Lock request

The following requests are illustrative contract examples. Replace account references and the lock identifier with resources from your environment.

POST /api/transactions HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer <access token>
API-Version: 1.0.0
Content-Type: application/json
Idempotency-Key: lock-inv-88421

{
  "txType": "LOCK",
  "assetId": "GBP",
  "accountRef": "ACC-0001",
  "counterpartyRef": "ACC-0002",
  "amount": "100.00",
  "params": {
    "expiry": "2027-01-01T00:00:00Z",
    "lockRef": "INV-88421"
  }
}

The first response is 202 Accepted; replaying the same key returns 200 with the current operation. Read GET /api/transactions/{transactionId} for the outcome.

Release to the destination

POST /api/transactions HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer <access token>
API-Version: 1.0.0
Content-Type: application/json
Idempotency-Key: release-inv-88421

{
  "txType": "RELEASE",
  "params": {
    "lockId": "b28f1a4c-9d3e-4f27-8a56-1e0c7b9d42a1"
  }
}

The first response is 202 Accepted; replaying the same key returns 200 with the current operation. Read GET /api/transactions/{transactionId} for the outcome.

Cancel back to the source

POST /api/transactions HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer <access token>
API-Version: 1.0.0
Content-Type: application/json
Idempotency-Key: cancel-inv-88421

{
  "txType": "CANCEL",
  "params": {
    "lockId": "b28f1a4c-9d3e-4f27-8a56-1e0c7b9d42a1"
  }
}

The first response is 202 Accepted; replaying the same key returns 200 with the current operation. Read GET /api/transactions/{transactionId} for the outcome.

Errors to handle

SituationResponseAction
Lock identifier not yet visible404 on release/cancelRetry the same completion key; the creating lock's row can appear after submission.
Lock exists but is not active, or another completion is in flight400Read and reconcile the existing operations.
Extra assetId, accountRef or amount on release/cancel400Send only txType and params.lockId.
Lock expiry is invalid or in the pastAccepted, then FAILED with UNPROCESSABLECorrect the expiry and use a new key after reconciling the failed operation.
Submission response is lostNo responseReplay the same key to recover the existing operation; do not create another lock.

Keep the lock obligation in your bank records

Your adapter owns the business commitment, beneficiary and remaining amount; Quant Flow applies the supported lock/release/cancel operation and reports settlement. Store lockId when returned and retain every related operation ID. There is no external lock-list endpoint, so keep the inventory recoverable in the bank's system.

Before releasing or cancelling, reconcile the known lock and settled changes. Acceptance is not evidence that funds are available again. Hand over outstanding locks during Maintenance and recovery and Access changes and offboarding, and verify outcomes before retiring the integration.

Access requirements

  • There is no dedicated lock-list endpoint. Store params.lockId from submission or recover it by listing LOCK operations and reading each operation. lockId is different from your lockRef.
  • Account freeze and unfreeze use POST /api/accounts/{accountRef}/controls. See Institutions, customers and accounts. They cannot be submitted as token transfers.
    Confirm the caller's token-operation entitlement, active custody configuration and contract authority with the operator before enabling these actions. Use independent named approvers for instructions held by policy.

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


Did this page help you?