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

# Transfers introduction

> Why moving money takes several calls, what each one buys you, and which failures happen where.

Creating a transfer is a small call. Getting to the point where you can make it is most of the integration, and that is deliberate: every check that can happen before money moves does.

## What each step buys

| Step | Buys you |
| - | - |
| [Destination](/services/recipients/overview) | Proof the target can receive, and the name the bank holds for it |
| [FX quote](/services/transfers/cross-currency-transfers) | A locked rate, bound to this transfer |
| [Preview](/api-reference/transfers/preview-a-transfer) | The fee and the exact `totalDebit`, with no side effects |
| Transfer | The movement itself |

Skip preview and you are asking a payer to approve an amount you have not calculated. Skip the destination and there is nothing to spend — a transfer takes a `destinationId`, never an account number.

## Where things fail

Failures cluster, and knowing which step owns which failure makes them much easier to handle.

| Failure | Surfaces at |
| - | - |
| Target cannot receive | Destination |
| Currency pair not convertible | FX quote |
| Amount below the route minimum | Preview or transfer |
| Fee makes the total unaffordable | **Transfer only** |
| Approval policy | Transfer |
| Provider unreachable | Quote or transfer |

The middle row is the one to plan for. **Preview does not check the balance**, so a preview can succeed and the transfer can still fail with `insufficient_funds` a moment later.

## Same currency or not

The two paths differ by one object.

```jsonc theme={null}
// Same currency: no quote. Send the amount for the side you fixed.
{ "sourceAccountId": "01K…", "destinationId": "01K…",
  "sourceCurrency": "NGN", "destinationCurrency": "NGN",
  "amountSide": "source", "sourceAmount": "2500000",
  "externalReference": "payout_001" }

// Cross-currency: a quote is required, and it carries both amounts.
{ "sourceAccountId": "01K…", "destinationId": "01K…",
  "sourceCurrency": "NGN", "destinationCurrency": "USD",
  "amountSide": "source", "sourceAmount": "2500000",
  "fxQuoteId": "01K…",
  "externalReference": "payout_002" }
```

Omit `fxQuoteId` when the currencies differ and you get `409 fx_quote_required`. Send one that was quoted for a different account, destination, side, or amount and you get a mismatch.

## Where the money goes

Three destination shapes, decided when the destination was created, not here:

* **`own_account`** — between your own accounts. Settles internally, usually `completed` immediately.
* **`sakawave_tag`** — to any Sakawave account by its public handle, including your customers' wallets.
* **`external`** — out to a bank or mobile-money account, over a route. This is the one that takes time and can fail at a provider.

The transfer object reports which it was in `destinationType`, and carries a snapshot of the destination in `destination` — so history stays readable even after a recipient is deleted.

## Asynchronous by default

An external transfer returns `pending`. It has been accepted and submitted; settlement happens afterwards.

Do not poll it in a loop. Subscribe to `fiat.withdrawal.completed` and `fiat.withdrawal.failed`, and treat [`GET /v1/transfers/{transferId}`](/api-reference/transfers/get-a-transfer) as the authority when you need to check — a webhook can arrive out of order, the resource cannot be wrong.

## The shape of the API

| Operation | Notes |
| - | - |
| [`POST /v1/fx-quotes`](/api-reference/fx-quotes/create-an-fx-quote) | Lock a rate. Cross-currency only. |
| [`GET /v1/fx-quotes/{quoteId}`](/api-reference/fx-quotes/get-an-fx-quote) | Read one, and whether it is spent. |
| [`POST /v1/transfers/preview`](/api-reference/transfers/preview-a-transfer) | Fee and total, no side effects. |
| [`POST /v1/transfers`](/api-reference/transfers/create-a-transfer) | Move the money. |
| [`GET /v1/transfers`](/api-reference/transfers/list-transfers) | Fixed filters, page size 20. |
| [`GET /v1/transfers/{transferId}`](/api-reference/transfers/get-a-transfer) | One transfer, with source account. |

There is no cancel, no amend, and no approve. A transfer is created and then observed.


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