Make a transfer

For integration engineers. Transfer GBP tokens from one customer's account to another's, follow the operation to CONFIRMED, and read both balances.

Who this is for

Engineers who have a funded ACC-0001 and an ACTIVE ACC-0002 from the earlier steps. By the end of this step 250.00 GBP has moved from CUST-0001 to CUST-0002.

How a transfer works

A TRANSFER moves tokens from the account in accountRef to the account in counterpartyRef. It is the one operation type that requires a counterparty.

  • Both references name accounts, never customers.
  • Both accounts must exist, hold the operation's assetId, and be ACTIVE.
  • The asset must have an ACTIVE contract.

The balance is not checked at submission. A transfer for more than ACC-0001 holds is accepted with 202 and fails during settlement. Check available first if your process needs to refuse early.

Like every token operation, a transfer is accepted first and settles asynchronously. Neither balance changes until it reaches CONFIRMED.

Carry the transfer into your integration

Store the bank's payment reference alongside the source account, beneficiary account, asset, amount and returned operation ID. Validate bank-side customer/payment checks before submission. Quant Flow executes the supported token transfer; it does not complete a separate cash payment in your core banking system.

Expose pending and terminal outcomes separately to the caller of your adapter. Persist signed events before acknowledging them, use operation reads to recover missing events and reconcile both accounts after confirmation. Approval, signing and settlement failures need their documented handling; elapsed time alone does not justify a second transfer. Use Production readiness for evidence and Daily operations and monitoring for ongoing checks.

Worked example

Submit the transfer

POST /api/transactions HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer eyJraWQiOiJ...
API-Version: 1.0.0
Content-Type: application/json
Idempotency-Key: a61e3b27-0d94-4c58-b7f2-6e8d1c0a4b39

{
  "txType": "TRANSFER",
  "assetId": "GBP",
  "accountRef": "ACC-0001",
  "counterpartyRef": "ACC-0002",
  "amount": "250.00"
}

Illustrative example built from the schema.

HTTP/1.1 202 Accepted
Content-Type: application/json

{
  "transactionId": "5b2e8d41-9c07-4a63-8e15-7f3a0d6c2b98",
  "txType": "TRANSFER",
  "assetId": "GBP",
  "accountRef": "ACC-0001",
  "customerRef": "CUST-0001",
  "counterpartyRef": "ACC-0002",
  "amount": "250.00",
  "params": {},
  "state": "POLICY_PENDING",
  "createdAt": "2026-08-06T10:04:31.207Z",
  "updatedAt": "2026-08-06T10:04:31.207Z"
}

A transfer carries no named call arguments, so params is {} when none were supplied. The example illustrates the policy-enabled path; a transfer accepted without policy starts in BATCHED.

Follow it to a terminal state

GET /api/transactions/5b2e8d41-9c07-4a63-8e15-7f3a0d6c2b98 HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer eyJraWQiOiJ...
API-Version: 1.0.0

Illustrative example built from the schema.

{
  "transactionId": "5b2e8d41-9c07-4a63-8e15-7f3a0d6c2b98",
  "txType": "TRANSFER",
  "assetId": "GBP",
  "accountRef": "ACC-0001",
  "customerRef": "CUST-0001",
  "counterpartyRef": "ACC-0002",
  "amount": "250.00",
  "params": {},
  "state": "CONFIRMED",
  "txHash": "0x2c7e9a1f4b8d3065e1a7c9f2b5d8e0a3c6f9b2d5e8a1c4f7b0d3e6a9c2f5b8e1",
  "blockNumber": 18447012,
  "createdAt": "2026-08-06T10:04:31.207Z",
  "updatedAt": "2026-08-06T10:06:02.884Z"
}

Read both balances

GET /api/accounts/ACC-0001/balances HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer eyJraWQiOiJ...
API-Version: 1.0.0

Illustrative example built from the schema.

{
  "accountRef": "ACC-0001",
  "customerRef": "CUST-0001",
  "assetId": "GBP",
  "total": "750.00",
  "available": "750.00",
  "locked": "0.00",
  "asOf": "2026-08-06T10:06:10.032Z"
}
GET /api/accounts/ACC-0002/balances HTTP/1.1
Host: api.qfp.quantnetwork.net
Authorization: Bearer eyJraWQiOiJ...
API-Version: 1.0.0

Illustrative example built from the schema.

{
  "accountRef": "ACC-0002",
  "customerRef": "CUST-0002",
  "assetId": "GBP",
  "total": "250.00",
  "available": "250.00",
  "locked": "0.00",
  "asOf": "2026-08-06T10:06:10.518Z"
}

View in API Reference

Errors and edge cases

Status or outcomeWhenWhat to do
400counterpartyRef omitted; either account does not exist, holds a different asset or is not ACTIVE; amount not positive or too precise; the asset has no ACTIVE contract; Idempotency-Key missing or invalidFix the request. Do not retry unchanged
200 instead of 202The Idempotency-Key was already usedThe body is the first operation as it now stands. No second transfer was created
state: FAILED after 202The transfer did not settle, for example because ACC-0001 did not hold enoughRead failureCode and reasonCode. See Handle failures
state: HELD or AWAITING_APPROVALAn insufficient-balance gate parked it, or policy/custody requires an approverSee Policy, approvals and audit

An inactive counterparty:

Illustrative example built from the schema.

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "timestamp": "2026-08-06T10:04:31.207Z",
  "status": 400,
  "error": "Bad Request",
  "message": "Account 'ACC-0002' is PENDING; token operations require an active account."
}

To hold funds for a counterparty and pay them later (for example on delivery), use a LOCK and a RELEASE. See Transfers, locks and releases.

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?