Skip to main content
This is an enterprise-only feature. Please contact us to enable.
Flow payments let your users pay from a supported wallet, exchange, or deposit address, and the funds settle in the token and chain you configure. This guide covers wallet and deposit-address payments with the Dynamic Flutter SDK. Payment lifecycle and states explains how a payment moves from creation to settlement.

Prerequisites

Before starting a flow on the client, create it from your backend. The flow creation endpoint is server-side only, authenticated by an API token with flow.write scope: this is where the amount, currency, settlement, and destination are fixed. Set currency to "USD" for a fiat amount, or "SETTLEMENT_TOKEN" to denominate the amount in the settlement token’s units: cryptocurrency is accepted only for payment flows whose settlement config lists exactly one token. Amounts you will see explains how the requested, quoted, and delivered amounts differ.
The response includes flow.id: pass this as the flowId to your Flutter app when calling the SDK methods below.
Optional: add your own fee. Add a feeConfig to the create body to take a percentage of the payment for yourself or for your own customers. Recipients can be EVM or Solana addresses, with at most one recipient per address family. The fee applies to deposit-address payments and to wallet payments that need a swap. Direct wallet transfers and exchange payments carry no fee. Adding your own fee explains when the fee applies, and the Fees API gives the config shape and how to claim fees.
Optional: generate a payment link instead. If you’d rather send the payer a URL than wire the create step into your own app, call POST /server/{environmentId}/payment-links instead of the create-flow endpoint above. It takes the same body plus a required baseUrl, and returns a paymentUrl you can send directly. Decode the flow query parameter on that page to recover the flowId, then continue with the SDK methods below starting at source attachment. See Payment Links for the hosted, self-hosted, and custom domain options for baseUrl.
Optional: disable swaps. Add disableSwaps: true to the create body when the source must already match a configured settlement. See Disable swaps for quote-time behavior and error handling, and Accept a same-token payment for a complete example.

Installation

The dynamic_sdk_fireblocks_flow package is available from Dynamic Flutter SDK 1.14.0 onward. Add it to your pubspec.yaml:
For EVM sources you also need dynamic_sdk_web3dart:
For Solana sources you need dynamic_sdk_solana:
Then run:

Supported chains

The Flutter SDK supports the following source chains:
  • BTC
  • EVM
  • SOL
  • SUI
  • TRON
TRON cross-chain swaps currently route through intent-based bridges and may incur higher gas costs relative to the transfer amount.

Overview

The client-side flow follows these steps:
  1. Attach the source wallet or deposit address with attachSource.
  2. Quote the conversion with getQuote.
  3. Prepare the unsigned source-chain payload with prepareSigning.
  4. Sign and broadcast the payload with the source wallet’s own signer.
  5. Record the resulting transaction hash with broadcast.
  6. Poll for completion with getFlow.
attachSource returns a session token (dft_…). The SDK persists it to secure storage keyed by flowId and adds it automatically to every subsequent call. You never need to handle it directly.

Resume a flow from its current state

A flowId represents one execution attempt. On page load, retry, or reconnect, call getFlow before calling a mutation. Do not unconditionally call attachSource again.
source_confirmed means source execution is finished, not necessarily that settlement is finished. Keep tracking settlementState until it reaches completed or failed.
Expiry and cancellation explains when a flow expires and who can cancel it.

Full example

flowId and wallet come from your app state. wallet is a BaseWallet returned by the Dynamic SDK.

Chain-specific signing

Step 4 (sign and broadcast) is not an API call. You sign prepared.signingPayload with the source wallet’s own signer and submit the result to the chain. The SigningPayload exposes one chain-specific field:
  • EVM → evmTransaction (and optional evmApproval)
  • SOL / SUI → serializedTransaction (base64)
  • BTC → psbt (base64-encoded unsigned PSBT)
  • TRON → tronTransaction

EVM source

If evmApproval is present, submit the ERC-20 approval transaction first and wait for it to be mined before signing the main evmTransaction.

Solana source

Bitcoin source

TRON source

Deposit address source

With a deposit address flow the user sends funds directly to a generated address: no wallet connection or on-chain signing required from your app. Works for BTC, SOL, EVM, and TRON.
1

Attach a deposit address source

2

Get a quote: response includes the deposit address

The quoted amount is valid for 60 seconds. The address stays open until the flow ends, but the deposit provider guarantees the quoted amount for only 60 seconds. If the user has not sent funds by then, call getQuote again to refresh the amount. A new quote for the same chain and token usually keeps the same address.
3

Poll until the transfer is detected

Dynamic watches the address. Poll getFlow until executionState leaves quoted.
The flow moves to source_detected when the deposit is seen, and then to source_confirmed when it is confirmed. If no deposit arrives before the flow expires, it moves to expired. After it leaves quoted, keep polling as shown in Polling for status until settlement completes or fails.
There is no signing or broadcast step for a deposit address, and calling broadcast on a deposit-address flow fails. Funds sent to the address after the flow is cancelled or expired can still reach your destination without the flow recording them. See Expiry and cancellation.

Resuming after an app restart

The session token returned by attachSource is persisted to secure storage automatically. To resume tracking an in-flight flow after the app was killed, call getFlow: it needs no session token:
If a later call throws FireblocksFlowException with sessionTokenInvalid == true, the stored token has expired or was rejected and has already been removed. Before the payment is sent, call attachSource again to obtain a new token. After the payment is sent, the app only needs to read the flow with getFlow.

Error handling

All Fireblocks Flow methods throw FireblocksFlowException on failure. The exception exposes message, statusCode, and sessionTokenInvalid. Use sessionTokenInvalid to decide whether to re-run attachSource.

Common errors

API errors lists every rejection the API returns for each request.

Polling for status

After broadcast, poll getFlow to track execution and settlement. Stop when settlementState reaches completed or failed, or when executionState reaches a terminal state (cancelled, expired, failed).
Last modified on October 28, 2026