# Track funding flows

Follow deposits and withdrawals from submission through confirmations, delivery, and settlement using lifecycle reads.

Use lifecycle reads to determine where a deposit or withdrawal is, what has happened, and whether processing succeeded. An accepted withdrawal request or a confirmed source transaction starts the journey; neither proves the destination received the funds.

On Testnet, call these reads on `https://api.testnet.polyester.com`; Mainnet is coming soon. For submission, follow [Deposits](https://testnet.polyester.com/docs/developer-docs/funds-transfers/deposits), [Withdraw from Trading](https://testnet.polyester.com/docs/developer-docs/funds-transfers/withdraw-from-trading), or the [funds transfer overview](https://testnet.polyester.com/docs/developer-docs/funds-transfers/overview).

## Find the flow

Choose the operation by the identifier you have. The references contain request schemas and filters.

- **Account history:** [`ListFlows`](https://testnet.polyester.com/docs/api-docs/connect/chain.lifecycle.v1.LifecycleReadService/ListFlows), REST [`GET /v1/chain/flows`](https://testnet.polyester.com/docs/api-docs/rest/GET/v1/chain/flows). Select the account by its account ID or smart-account address, then narrow by kind, Network, or Asset.
- **On-chain transaction:** [`ListFlowsByTx`](https://testnet.polyester.com/docs/api-docs/connect/chain.lifecycle.v1.LifecycleReadService/ListFlowsByTx), REST [`GET /v1/chain/flows/by-tx/{tx_hash}/matches`](https://testnet.polyester.com/docs/api-docs/rest/GET/v1/chain/flows/by-tx/tx_hash/matches). Use `TX_SOURCE` for the original source transaction or `TX_ANY` for the source or latest activity reference.
- **Known flow:** [`GetFlowById`](https://testnet.polyester.com/docs/api-docs/connect/chain.lifecycle.v1.LifecycleReadService/GetFlowById), REST [`GET /v1/chain/flows/{flow_id}`](https://testnet.polyester.com/docs/api-docs/rest/GET/v1/chain/flows/flow_id). Save the public `flowId` from a list or transaction match and use it for subsequent detail reads.

A transaction can match zero, one, or several flows. For a deposit with several legs, inspect every match and distinguish occurrences using `txOccurrenceIndex`, the Asset, account, and route. An empty result does not prove the transfer failed or never happened.

Follow `nextPageToken` until empty. Keep the filters and ordering unchanged while following a page cursor. For later polling, start a fresh list: the default last-activity ordering changes as flows progress.

### Match a withdrawal request

Persist the withdrawal's idempotency key, signed payload, account, destination, and returned `intentId`. The withdrawal response acknowledges acceptance, rather than delivery.

`GetFlowById` requires a public `flowId`; do not pass `intentId` or construct a flow ID from it. Use `ListFlows` for the source account, including open and terminal flows. Compare the route, Asset, gross amount, destination, and submission time. Once a transaction reference is available, use `ListFlowsByTx` to narrow the candidates.

These comparisons are candidate matching, not a unique request identifier. If several withdrawals look identical, keep them unresolved and contact Polyester support with their saved intent IDs. Do not submit a replacement withdrawal to obtain a clearer match.

### Identify the route and Asset

Flow kinds describe the family:

- **`KIND_DEPOSIT`:** deposits into Polyester.
- **`KIND_WITHDRAW`:** withdrawals out of Polyester-controlled balances or accounts.
- **`KIND_TRANSFER`:** transfers between Polyester accounts.

Use the flow's source and destination domains for route labels, such as Funding to Trading or Trading to an external Network. Do not infer the whole route from one intermediate milestone.

The flow's `assetIds` identifies the Asset and its chain-specific mapping. Its `sourceAddress` and `destinationAddress` describe the movement; they are not token contract addresses. Resolve token contracts through [`GetDepositWithdrawConfig`](https://testnet.polyester.com/docs/api-docs/connect/chain.zipper.v1.ZipperService/GetDepositWithdrawConfig) ([`GET /v1/chain/deposit-withdraw/config`](https://testnet.polyester.com/docs/api-docs/rest/GET/v1/chain/deposit-withdraw/config)).

Lifecycle responses use the protobuf-style views, including `amountE18`: gross principal in 18-decimal units, separate from the request fee. Delivery activities can show net amounts. Use [scaled integers](https://testnet.polyester.com/docs/developer-docs/connectrpc/scaled-integers) when decoding these values.

## Read progress and the outcome

`ListFlows` supports these state filters:

- **`STATE_PENDING_SOURCE`:** waiting for source-Network progress.
- **`STATE_PENDING_POLYESTER_CHAIN`:** progressing on Polyester Chain.
- **`STATE_PENDING_LEDGER`:** waiting for balance posting or settlement.
- **`STATE_COMPLETED`:** completed successfully.
- **`STATE_FAILED`:** failed and no longer progressing.
- **`STATE_DROPPED`:** stopped before successful completion.
- **`STATE_REFUNDED`:** ended in a refund or reversal.

These are `flowState` filter values. Returned summaries expose `currentStep`, `isOpen`, and `isTerminal`, rather than a `flowState` field. To select successful completions explicitly, list with `STATE_COMPLETED` and `LIST_TERMINAL_ONLY`, then match the saved `flowId` across the pages. Use `LIST_ALL` for reconciliation so that completed or failed flows are not excluded.

> **Terminal does not mean success**
>
> `isTerminal` means the flow reached a final processing state. Read its outcome, observed milestones, `lifecycleReason`, and any `zipperReason` details before marking it successful or deciding to send funds again. A failed withdrawal does not by itself prove that its funds have been returned.

Terminal is not a promise that later evidence can never arrive. A deposit marked `DEPOSIT_SOURCE_NOT_CONFIRMED` can resume and complete if its source transaction confirms later. Retain its transaction and flow IDs for reconciliation.

### Milestones versus estimates

A detail read separates factual `observedSteps` from the summary's projected `progressTimeline`. The current step can be ahead of the last observed milestone. A planned or projected step is not proof of execution.

The steps that apply depend on the route:

- **Source:** `FLOW_STEP_SOURCE` tracks the external transaction and confirmations.
- **Request and validation:** `FLOW_STEP_REQUEST` and `FLOW_STEP_VALIDATION` cover request creation and approval. Approval and rejection counts describe validation progress.
- **Transfer or execution:** `FLOW_STEP_TRANSFER` covers deposit crediting; `FLOW_STEP_EXECUTION` covers execution on Polyester Chain.
- **External delivery:** `FLOW_STEP_BRIDGE_FULFILLMENT` covers delivery progress. `FLOW_STEP_FULFILLING` means a withdrawal destination transaction hash is committed, with final fulfillment confirmation still pending. A hash alone is not completed delivery.
- **Settlement:** `FLOW_STEP_SETTLEMENT` confirms durable balance settlement where the route involves a ledger balance. Deposit activities distinguish credit to Funding from credit to Trading.
- **Unsuccessful endings:** `FLOW_STEP_FAILED`, `FLOW_STEP_DROPPED`, and `FLOW_STEP_REFUNDED` identify failure, dropping, or refund/reversal outcomes.

For an explorer link, use the milestone's transaction chain ID and that Network's configured explorer. A reference with no transaction chain ID can be a settlement identifier, not an on-chain transaction hash.

## Confirmations and timing

Follow the flow's current and required confirmation counts when they apply. Network configuration provides a default confirmation requirement and estimated average confirmation time when known; neither is a guarantee for this transfer.

Use the returned expected step durations and estimated completion time for progress displays. When `isDelayed` is true, there is no reliable ETA and the estimated completion timestamp is zero. Show the delay and continue reconciliation rather than displaying that timestamp as a date.

## Polling and streams

Polling `GetFlowById` is the direct way to follow a known flow. Refresh account lists to discover new flows, using bounded backoff and jitter. Honor any retry delay; see [rate limits](https://testnet.polyester.com/docs/developer-docs/shared-concepts/rate-limits).

Streams reduce polling. On the realtime connection, [account lifecycle flow summaries](https://testnet.polyester.com/docs/api-docs/streams/private-chain-lifecycle-flows) report changes to the flows of one Main Account or Subaccount, and [lifecycle flow detail](https://testnet.polyester.com/docs/api-docs/streams/public-chain-lifecycle-flow-detail) follows one `flowId` with its observed steps. Balance and ledger transfer streams report the resulting balance changes. Follow the [WebSocket session model](https://testnet.polyester.com/docs/developer-docs/shared-concepts/websocket-session-model) for authentication, recovery, and deduplication. The private order WebSocket carries orders, not funding lifecycles. Use lifecycle reads after reconnects or gaps and to confirm an outcome before updating your records.

## When progress stops or fails

1. Refresh the evidence

   Read the flow again. Check the last activity, observed milestones, confirmation counts, and the transaction on the correct Network. A delayed flow is still open; do not treat an estimate being missed as a failed operation.

2. Read the reason before changing anything

   For failed, dropped, or refunded flows, inspect the lifecycle reason and detailed outcome. For `TRADING_WITHDRAW_POLICY_DENIED`, review [API key and Subaccount policies](https://testnet.polyester.com/docs/developer-docs/account/api-key-policies). Verify the actual balance or external delivery before assuming a refund is spendable.

3. Reconcile before retrying or escalating

   A lost withdrawal response can leave the outcome unknown. Preserve its idempotency key and signed payload; follow [withdrawal retry rules](https://testnet.polyester.com/docs/developer-docs/funds-transfers/withdraw-from-trading) and [error handling](https://testnet.polyester.com/docs/developer-docs/error-handling/error-responses#retries-and-idempotency). If the result remains unclear, contact Polyester support with the flow ID, intent ID if available, transaction hash and Network, account, Asset, amount, destination, timestamps, and returned reason. Never include private keys, signatures, or authentication tokens.
