> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pesapay.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Transfer lifecycle

> Each transfer's stage path, and the SEP-24 status your app should show.

Every transfer is one row with one outcome. The API returns two fields: `stage`, the internal state, and `status`, a SEP-24 word that says whose turn it is.

## Stage paths

| Route | Path |
| - | - |
| `cctp-deposit` | `AWAITING_FUNDS → FUNDED → SOURCE_SIGNED → SOURCE_CONFIRMING → ATTESTED → STELLAR_ARRIVED → CREDITED` |
| `usdt0-deposit` | `AWAITING_FUNDS → FUNDED → TOPPED_UP → SOURCE_SIGNED → SOURCE_CONFIRMING → LZ_DELIVERED → SWAP_PENDING or SWAP_REQUOTE → STELLAR_SIGNED → CREDITED` |
| `cctp-withdraw` | `AWAITING_SIGNATURE → STELLAR_SIGNED → APPROVED → STELLAR_SIGNED → BURNED → ATTESTED → DEST_SUBMITTED → DELIVERED` |
| `usdt0-withdraw` | `FUNDED → TOPPED_UP → STELLAR_SIGNED → SWAPPED → STELLAR_SIGNED → SENT → LZ_DELIVERED → DELIVERED` |
| `stellar-send` | `AWAITING_SIGNATURE → STELLAR_SIGNED → DELIVERED` |

Deposits in `direct` mode start at `FUNDED`. A `deposit_address` deposit starts at `AWAITING_FUNDS` and moves to `FUNDED` when the address holds the quoted amount (polled every 10 seconds).

## Status

| `status` | Stages | Show the user |
| - | - | - |
| `pending_user_transfer_start` | `AWAITING_FUNDS` | "Send USDC to this address" |
| `pending_user` | `FUNDED`, `AWAITING_SIGNATURE`, `TOPPED_UP`, `APPROVED`, `SWAPPED`, `SWAP_PENDING`, `SWAP_REQUOTE` | "Approve in your wallet" |
| `pending_anchor` | `FUNDED` while Pesa tops up a fee | "Preparing" |
| `pending_external` | `SOURCE_SIGNED`, `SOURCE_CONFIRMING`, `DEST_SUBMITTED`, `SENT`, and on withdrawals `ATTESTED`, `LZ_DELIVERED` | "Confirming on the other chain" |
| `pending_stellar` | `STELLAR_SIGNED`, `STELLAR_ARRIVED`, `BURNED`, `SUBMIT_FAILED`, and on deposits `ATTESTED`, `LZ_DELIVERED` | "Confirming on Stellar" |
| `pending_trust` | `PENDING_TRUST` | "Add the asset to your wallet" |
| `on_hold` | `MANUAL_REVIEW` | "We are checking this transfer" |
| `completed` | `CREDITED`, `DELIVERED` | Done |
| `expired` | `EXPIRED`, `CANCELLED` | "Expired. Your funds are still in your wallet" |
| `error` | `UNATTRIBUTED` | "Contact support" |

`pending_user` means the next step is the user's. When you see it, call [`getActions`](/sdk/client-reference#getactions) and show the action.

## Shared rules

* **Expiry.** A transfer expires after 24 hours, or the user can cancel it, as long as nothing irreversible happened (no burn, no OFT send, no Stellar debit). Funds that never left stay in the user's wallet.
* **No refund edges.** A confirmed burn or OFT send can only finish.
* **Late burns still finish.** A valid burn submitted after expiry revives the transfer at `SOURCE_SIGNED`. Burn actions stop being issued 30 minutes before expiry.
* **Balance changes only on observation.** `CREDITED` needs an observed Stellar arrival. `DELIVERED` needs the destination transaction observed on its chain.
* **Manual review has an owner.** After 7 days in `MANUAL_REVIEW` with no match, a transfer becomes `UNATTRIBUTED`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.