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

# Payout Statuses, Notifications & Reports

> What each payout status and sub-status means, why DEDUCTED never reaches you, when the payout webhook fires and the two cases where it does not fire at all, how to detect a reversal, and what the daily, weekly and monthly payout reports contain and when they appear.

This page covers reading a payout after you have created it: its status, how you find out it
finished, and where the periodic reports are. Creating one is in the
[Payout FAQ](/docs/en/support/payout-faq); the request fields are in the
[Payout Request Field Guide](/docs/en/support/payout-request-field-guide); batch payouts have their own
statuses in [Batch payout statuses & funding](/docs/en/support/batch-payout-faq).

## Is payout creation synchronous or asynchronous?

Asynchronous, in every practical case. A successful create returns an order with
`status: IN_PROGRESS` and Waffo's `payoutOrderId`; the outcome arrives later. There are exactly
three ways to learn the outcome, and you should build on at least two of them:

| Route | Use it for |
| - | - |
| **`/api/v1/payout/inquiry`** | The authoritative current state, at any time, by `payoutRequestId` or `payoutOrderId` |
| **The payout webhook** | Being told promptly, without polling — see the limits below |
| **The Portal** | Investigating one order by hand |

A create can also come back already final: an identical resend of a `payoutRequestId` whose
original order has finished returns that final status straight away, and a payout that fails at the
pre-check step fails synchronously. Treat `SUCCESS` and `FAILURE` on a create response as real.

## What statuses can a payout have, and which are final?

| `status` | Meaning | Final? |
| - | - | - |
| `IN_PROGRESS` | Being processed | No |
| `SUCCESS` | The payout succeeded | Yes |
| `FAILURE` | The payout failed — read `failureCode` and `failureReason` | Yes |

Three values, and only two of them are final. There is no separate "submitted", "deducted" or
"accounting" value in the API.

## The Portal shows a different status from the API. Which is right?

They agree — the Portal payout list and detail render the **same three values** the API returns,
and the filter on the list offers the same three. Waffo tracks finer internal stages while a
payout is moving, and every one of them is reported to you as `IN_PROGRESS`; neither surface
exposes them. If the two genuinely differ, one of them is stale — re-inquire, and treat the
inquiry response as authoritative.

## I saw `DEDUCTED` somewhere. Has the money left?

`DEDUCTED` is an internal stage name, not a payout status you can receive: it is one of the
positions inside `IN_PROGRESS`. It means the funding has been taken from your settlement account
and moved into the Payout Wallet — **not** that the payee has been paid. Funds sit in the wallet
as *In Transit* from that point until the payout reaches a final status, which is why a payout can
show as deducted on your balance and still fail afterwards, returning the amount. That mechanism
is set out in [Payout Wallet & coverage](/docs/en/support/payout-wallet-and-coverage-faq).

## What is `subStatus`? What about `CONSULT_SUCCESS` and `CONSULT_FAILURE`?

`subStatus` is present **only** when a reversal has happened, and only ever carries one of two
values:

| `subStatus` | Meaning |
| - | - |
| `FULL_REVERSED` | The whole payout amount was reversed |
| `PARTIAL_REVERSED` | Part of the payout amount was reversed |

`CONSULT_SUCCESS` and `CONSULT_FAILURE` are internal markers for the pre-check step and are
**filtered out before the response is built** — the API returns a `subStatus` only for the two
reversal values, so you will never receive either of them. If you have seen them, they came from
somewhere other than the payout API, and they carry no meaning you need to act on.

## A payout succeeded. Can it still be reversed?

Yes. The receiving side can return a payout after it has already reached `SUCCESS`. When that
happens:

* `status` **stays** `SUCCESS`. It does not move to a failed or reversed status.
* `subStatus` becomes `FULL_REVERSED` or `PARTIAL_REVERSED`.
* The reversed amount is credited back to the account that funded the payout — your settlement
  account, in the funding currency. A partial reversal returns only the reversed part, so
  reconcile against the reversal, not the original payout amount.

**A reversal does not send a webhook.** No notification of any kind is pushed when a payout is
reversed. The only ways to find out are re-inquiring the order or looking at the Payout Wallet
account history, where the reversal posts its own pair of rows. If reversals matter to your
ledger, re-inquire successful payouts on a schedule rather than treating `SUCCESS` as the end of
the order.

## How do I read the fee fields?

| Field | Meaning |
| - | - |
| `feeCurrency` | The currency the fee is charged in |
| `actFeeAmount` | The fee actually taken, once the order is final |
| `feeStatus` | `DEDUCTED`, `RETURNED`, or `NONE` |

`actFeeAmount` and `feeStatus` move together:

| `feeStatus` | `actFeeAmount` | When |
| - | - | - |
| `DEDUCTED` | The fee amount | Charged and kept |
| `RETURNED` | `0` | Charged and given back |
| `NONE` | `0` | There was no fee |

A successful payout ends as `DEDUCTED` or `NONE`. A failed payout can be any of the three: the fee
comes back in full if the order never reached the receiving side, and otherwise comes back only
where your agreement for that method is marked **Fee Refundable = Yes** on the Service → Payout
page. So `feeStatus` is the field to reconcile against, not an assumption that a failure is free.

## Is the payout fee taken out of the amount, or charged on top?

On top. `payoutAmount` is what you asked to pay the payee; what leaves your settlement account is
`prefundAmount`, which is the converted payout amount **plus** that order's fee. The payee is not
funding the fee out of their payment.

## What exchange rate was used, and when was it fixed?

The payout response does not carry a rate. What it carries is the amounts on each side —
`payoutAmount` in the currency you requested, `prefundAmount` in the currency you were debited,
and `payeeAmount` in the currency the payee received — and neither the API nor the Portal payout
detail exposes a rate field. Reconcile from the amounts.

For a cross-currency payout, `payeeAmount` can legitimately be empty on an early inquiry and be
filled in later, because the exact received amount is not always known when the order is created.
Do not quote the payee a figure from a create response.

## Does the payout webhook exist? What is the event called?

Yes: `PAYOUT_NOTIFICATION`. It is delivered to the `notifyUrl` on that order — the URL is
per-request and mandatory for API payouts, with no account-level fallback. The body follows the
same envelope as every other Waffo webhook, with `result` structured exactly like the
`/api/v1/payout/inquiry` response, and is signed in the `X-SIGNATURE` header. Verification,
response format and retry behaviour are identical to the other events — see
[Signature verification](/docs/en/developer-docs/webhook/signature-verification) and
[Webhook retry](/docs/en/developer-docs/webhook/retry). Withdrawals have their own separate event,
`WITHDRAW_NOTIFICATION`; a payout webhook is never a withdrawal webhook or vice versa.

## When does it fire? Are there intermediate notifications?

Once, at the end, and never in between:

* It is pushed when the payout reaches `SUCCESS` or `FAILURE` **and** its fee accounting has
  completed — which is why `feeStatus` and `actFeeAmount` are already populated in the payload.
* There is **no** notification for `IN_PROGRESS`, and none for any internal stage.
* There is **no** notification for a reversal.

## Why am I not getting webhooks for my batch payouts?

Because the payout webhook is pushed **only for payouts created through the API**. A payout that
originated as a row in a Portal batch upload does not produce one, however it ends. Track batch
results from the batch record and its result file — see
[Batch payout statuses & funding](/docs/en/support/batch-payout-faq) — or from
`/api/v1/payout/inquiry` on the `payoutOrderId` of each row.

## What if I miss a webhook or return a non-200?

Waffo retries on a `failed` or `unknown` body, or on a delivery failure, on a fixed back-off
schedule; the attempts and intervals are on [Webhook retry](/docs/en/developer-docs/webhook/retry).
Respond `{"message":"success"}` once you have stored the event.

Because the payout webhook fires once and only at the end, a webhook you never process is an
outcome you never hear about. Do not run payouts on webhooks alone — reconcile with
`/api/v1/payout/inquiry` for any order you have no final status for.

## A payout has been `IN_PROGRESS` for a long time. When should I worry?

There is no published time after which an in-progress payout is abnormal, and the answer varies by
corridor, so treat duration alone as uninformative. What to do instead:

| Check | Why |
| - | - |
| Re-inquire the order | The status may already have moved and only the webhook is missing |
| `payoutUpdatedAt` | Tells you when the order last changed, which is more informative than how old it is |
| `payoutArrivalTime` | Populated only when the payout completes — empty means it has not |
| The status timeline on the Portal detail | Shows which stages have been reached |

Do **not** create a second payout to force it. A payout still in flight can complete, and the
second order is a second payment. Raise a stalled payout with Waffo using the `payoutOrderId`
rather than re-sending it.

## A payout failed. Do I resend the original or create a new one?

Create a new one, with a **new `payoutRequestId`**. Resending the same `payoutRequestId` returns
the original order together with its original failure code — it does not re-attempt the payout.
Read `failureCode` first and fix whatever it names; see
[Payout error codes & retries](/docs/en/support/payout-error-codes-and-retry-faq) for which codes are
worth re-sending at all.

## What do `payOption` and `channelId` mean on a payout record?

`payOption` is the specific receiving option resolved for the payout — the label behind a bank code,
for example. It appears on the Portal payout detail as **Payment Option** and is useful when you
need to confirm which of several routes a payout took to a bank.

`channelId` is not a merchant-facing field: it is not on the Portal payout detail and it is not in
the payout inquiry response. If you have it from somewhere, it is not something you need to
reconcile against.

## What periodic payout reports do I get?

Three, all under **Payout → Payout Report** in the Portal:

| Report | Period covered |
| - | - |
| **Daily** | One calendar day |
| **Weekly** | Monday to Sunday |
| **Monthly** | The 1st to the last day of the month |

The list shows, per report, the **Period**, the **Order Count** it covers, the **Generated Time**
(UTC+8) and the **File Name**, which is the download link. Filter by a date range and pick the
report type. Files are CSV.

## Can I get today's report today?

For the **daily** report, yes — it is the one report that may be generated on the day it covers,
as soon as that day's payout settlements have all finished settling. Weekly and monthly reports are only produced after
their period has **ended** — a weekly report does not exist mid-week. In every case a report needs
**both** conditions:

1. Its period has ended (daily: the day itself counts).
2. Every payout settlement in that period has **finished settling**. A period that has ended but
   still has unsettled payout activity is skipped and retried later.

That is why a period can end and its report still not be there yet, and why the list only ever
shows reports that were generated successfully — there is no pending or failed row to interpret. A
period with no payout activity at all produces no report rather than an empty one.

## Can payout reports be pushed to SFTP or emailed on a schedule?

**SFTP — yes, by arrangement.** Waffo can deliver a scheduled payout bill file for your account to
an SFTP location on a daily cycle. It is set up by Waffo per merchant account, not switched on in
the Portal: ask support, stating the account and the SFTP details you need. **Email — no.** There is
no payout-report email subscription. Independently of either, the payout report stays available as a
Portal download: open Payout → Payout Report and click the file name, which hands you a time-limited
download link. Settlement report delivery is a separate feature with its own SFTP and email options —
see [Report delivery & email subscription](/docs/en/support/report-delivery-and-subscription-faq) — so do
not assume a settlement subscription covers payouts.

## The report download link stopped working. How do I get a new one?

Click the file name again. The link is generated fresh each time and is deliberately short-lived,
so it is meant to be used immediately rather than stored, forwarded or embedded in a job. A link
that has expired is not an error condition — nothing has been lost.

Downloading requires the report-download permission on your Portal user. Without it you can see
the report row and its file name but the name is plain text rather than a link; ask your account
administrator.

## Can I export the payout lists? Is it synchronous?

Yes, and **asynchronous**. Both the single-payout list and the batch list export as a task: you
start it, and the file appears in the Portal's export area rather than downloading in the browser.
Statuses, retries and link expiry work the same as every other export — see
[Exports & report downloads](/docs/en/support/export-center-faq).

Two limits to plan around:

| Limit | Value |
| - | - |
| Export date range | One month maximum — a wider selection is rejected before a task is created |
| Query date range | Payout list queries are also restricted to a one-month window |

A very large export is split across multiple files rather than truncated, so check for more than
one file before concluding data is missing.

## Should I reconcile from the reports or from the API?

Use whichever matches the grain of what you are reconciling, and expect them to describe different
things:

| Source | Grain | Best for |
| - | - | - |
| `/api/v1/payout/inquiry` | One order, current state | Per-order truth, including reversals |
| Payout list export | Orders in a date range | Your own order-level ledger |
| Payout Report | A settled period | Tying payouts to what actually cleared |

When two sides do not agree, the fields that usually explain it are `prefundAmount` versus
`payoutAmount` (the first includes the fee and is in the funding currency), `actFeeAmount` with
`feeStatus` (a failed payout may or may not have returned its fee), and `subStatus` (a reversal
changes the money without changing `status`). Check those three before raising a discrepancy.

## Can Waffo give the payee an invoice or a payment receipt?

There is no payee-facing receipt or invoice produced for a payout. What the payee sees is the
`description` you sent, on their bank or wallet statement. On your side the evidence of a payout is
the order record, the payout list export and the Payout Report. If you need to give a payee a
document, generate it from the order data — `payoutOrderId`, `payeeAmount`, `payeeCurrency`,
`payoutArrivalTime` and `description` are the fields that identify the payment.

***

Statuses or reports not matching what you expect?
[Contact support](mailto:support@waffo.com) with the `payoutOrderId`, or the report period and
type.


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