Skip to main content
This is an enterprise-only feature. Please contact us to enable.
This tutorial builds a checkout where the customer pays the exact token you settle in. You create a payment flow with disableSwaps, Flow issues a deposit address on the settlement chain, the customer transfers the token to it, and Flow forwards the funds to your destination wallet. There is no quote through a swap provider and no conversion: the customer sends USDC on Base, you receive USDC on Base. Use this when your customers already hold the token you want to receive. To accept any token or chain, see the Flow API guide for the full swap flow.

Prerequisites

  • A Dynamic environment with Fireblocks Flow enabled
  • An environment API token (dyn_...) with flow.write scope from Developer > API Tokens in the developer console
  • A wallet address on the settlement chain where funds should land
  • Node.js 18+ (or any runtime with fetch)
The API base URL is https://app.dynamicauth.com/api/v0.

Step 1: Create the flow

Create the flow from your backend with mode: "payment" and disableSwaps: true. The amount, currency, settlement, and destination are fixed here and cannot be changed later.
The response returns the created flow. Store flow.id: your payer page needs it for the next steps, and your backend uses memo to reconcile the payment later.
With disableSwaps: true, the quote fails with 422 if the payer’s source token or chain differs from a configured settlement. List every token and chain you accept in settlementConfig.settlements.
To set how long the checkout stays open, pass expiresIn (seconds) at creation. The default is 86400 seconds (24 hours).

Step 2: Attach a deposit address source

On your payer page, attach a deposit_address source to the flow. This call needs no authentication: it mints the flow session token (dft_...) that drives the remaining steps.
  • fromChainName and fromChainId must match a chain in your settlementConfig.settlements.
  • refundAddress is required. If the deposit cannot be delivered, funds return here.
  • fromAddress is not accepted for a deposit_address source: the payer is not connecting a wallet.
Store sessionToken immediately. It is returned once, with Cache-Control: no-store, and expires at sessionExpiresAt.

Step 3: Get the deposit address

Fetch the quote with the session token. For a deposit address source this call mints the deposit address and returns it on the flow.
The flow moves to executionState: "quoted" and returns:
  • flow.depositAddress: the address the customer sends funds to
  • flow.quote.fromAmount: how much of the source token the customer must send
  • flow.quote.expiresAt: how long the quote is valid

Step 4: Show the payer the address

Render depositAddress and quote.fromAmount with the token symbol and chain so the customer knows exactly what to send and where. A QR code of the address works well for mobile wallets. A deposit address is not reusable across flows: mint a fresh flow for each checkout. If you call quote again on the same flow, the same address comes back rather than a new one.
There is no prepare, sign, or broadcast step for a deposit address source. The customer pays with any wallet or exchange that can send the settlement token on the settlement chain.

Step 5: Detect the payment

Flow watches the deposit address and advances the flow on its own. Execution moves to source_detected when the transfer arrives and source_confirmed once it confirms on chain. Two ways to learn about it: webhooks (recommended) or polling.

Webhooks

Subscribe your backend to the flow events: See Webhooks and events for the payload shapes and Webhook setup for endpoint configuration and signature verification.

Polling

For a prototype or low-volume checkout, poll the read endpoint until the flow reaches a terminal state. It needs no authentication.

Step 6: Confirm the payment

Treat settlementState: "completed" as paid. Execution reaching source_confirmed only means the customer’s transfer landed at the deposit address; settlement can still be in progress. When the settlement completes, reconcile the payment:
  • Match flowId and the flow’s memo (for example orderId from Step 1) to your internal order.
  • Record settlementTxHash from the flow.settlement.updated payload (or the polled flow) as the on-chain receipt.
  • flow.settlement.completedAt is the timestamp the funds reached your destination.
If the flow reaches cancelled, expired, or failed, the checkout attempt is over. Create a new flow for another attempt. If you do not want to build the payer page, create a payment link instead of calling the flow endpoint directly:
The body is the same as Step 1 plus a required baseUrl (your hosted payer page origin, which must be a registered CORS origin for the environment). The response returns a paymentUrl to send to the customer. See Payment Links.

Common pitfalls

  • Do not send Authorization: Bearer on /sdk/ endpoints. Only the /server/ creation endpoints accept the API token; SDK endpoints use X-Dynamic-Flow-Session-Token or no auth.
  • Quote fails with 422. The payer’s fromChainName or fromChainId does not match a configured settlement, or a swap would be required while disableSwaps is set.
  • 409 on a mutation. The flow moved past that step. Fetch the flow and resume from its current executionState rather than replaying the call.
  • Wrong token or chain sent. A transfer of a different token to the deposit address is not detected as payment for this flow. The payer’s refund path is the refundAddress from Step 2.

Next

Flow API guide

Webhooks and events

Settlements

Last modified on September 23, 2026