Skip to main content
The safest transfer workflow persists intent before making an API call. Store your unique externalReference, source account, destination, amount, and currency together.

1. Create a destination

For an own-account transfer:
Destinations expire. Create a new one if the returned expiresAt has passed. For an external payout, first call GET /v1/transfer-corridors?currency=KES&country=KE. Render the returned field descriptors, then either create an inline destination or save a recipient and payment detail for reuse. Provider selection stays internal to Sakawave.

2. Create an FX quote when needed

Skip this step when source and destination currencies match. Otherwise, send exactly one of sourceAmount or destinationAmount, matching amountSide.
Use the quote before expiresAt. Supply its id as fxQuoteId when previewing and creating the matching transfer.

3. Preview fees and total debit

Confirm fee, totalDebit, currencies, and destination with your user before creating the transfer. Request amounts use minor units; preview amounts are returned as decimal strings.

4. Create the transfer

Reusing externalReference returns the existing transfer. It does not validate that a later payload matches the original, so never reuse a reference for a different payment.

5. Handle the lifecycle

API keys can initiate transfers but cannot approve or reject them. Handle statuses as follows:
  • awaiting_approval: a human approver must act through an approved non-API-key flow.
  • submitting: transient; poll with backoff if necessary. This status is not published as a webhook event.
  • pending: accepted but not final.
  • completed: final success unless a later reversal occurs.
  • failed, rejected, reversed: do not mark paid; inspect failureCode and failureReason.
Use signed webhooks for state changes and periodic retrieval as a recovery path. Then reconcile the transaction.