> ## 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.

# Settlement Calculation Explained

> Reproduce a Waffo settlement figure line by line: the four clearing steps, the 2 vs 6 decimal precision setting, which currency pair and rounding rule each currency combination uses, how minimum and maximum fee caps are applied, what a Return Fee is, and why a negative settlement period pays nothing.

This page is for the case where you are trying to **reproduce a settlement figure
yourself** and your arithmetic does not match ours. It works bottom-up: one
transaction, four steps, then the rounding and the currency pair that apply to
your particular currency combination.

For the report-level view — which column comes from where, how to export it, and
why a file may be missing — see
[Settlement Reports & Exports](/docs/en/support/settlement-reports-faq). For the dates
the money moves on, see [Settlement Cycle & Calendar](/docs/en/support/settlement-cycle-faq).
For the balances it lands in, see
[Balances & Account History](/docs/en/support/balance-and-account-history-faq).

## How does Waffo get from my order amount to my settlement amount?

Every transaction goes through the same four steps, in this order:

| Step | What happens | Result |
| - | - | - |
| 1 | **Clearing amount** — the order amount is converted into your settlement currency | `Order Amount (Settlement Currency)` |
| 2 | **Tax deducted inclusively** — transaction taxes (VAT and/or withholding tax) are computed and deducted from the clearing amount | `Tax Amount` (the report column is labelled `Tax Amount`, whichever tax it is) |
| 3 | **Fee deducted inclusively** — the processing fee is computed and deducted from the clearing amount | `Fee Amount` |
| 4 | **Net settlement** — what is left | `Settlement Amount` |

```
Settlement Amount = Clearing amount − tax deducted − fee deducted
```

Two properties of this order matter when you reconcile:

* **Taxes and fees are inclusive (deducted from the order amount), not added on
  top.** The base for both the tax and the fee calculation is the order amount as
  transacted, not the amount net of the other one. They are not compounded.
* **The clearing amount is produced first, and tax and fee are then each computed
  through their own currency pair.** So a fee billed in a third currency is not
  derived from the already-converted settlement figure — see the case tables
  below.

## What decimal precision does my settlement use, and can I change it?

`Settlement Decimal Place` is set on your merchant profile when you are signed
up. It has two possible values — **2 decimal places** or **6 decimal places** —
and **it cannot be changed afterwards**.

| Value | Fee, tax and clearing amounts in the detail report | Fee rounding | Settlement Amount |
| - | - | - | - |
| 2 decimal places | 2 decimals | Rounded **up** (`ROUNDUP2`) | 2 decimals |
| 6 decimal places | 6 decimals, zero-padded | Rounded **half up** at 6 decimals | 6 decimals in the detail file; 2 decimals at batch level |

Regardless of the setting:

* **Exchange rates always carry 8 decimals**, zero-padded if the rate is shorter.
* **The settlement summary figure is always 2 decimals.** Money moves in
  2 decimals.

If you are on 6 decimals, the sum of your detail rows and the batch amount agree
to the cent, because the residual between the 6-decimal sum and the 2-decimal
batch figure is tracked explicitly rather than being silently dropped:

```
6-decimal total = 2-decimal batch amount + residual
```

If you are on 2 decimals, each row is already rounded to 2 decimals before being
summed, so small-ticket transactions are where you will see the largest relative
difference from a 6-decimal calculation — this is the reason the 6-decimal option
exists.

## Which currency pair and which rounding rule apply to my transactions?

Three currencies are in play: your **order currency**, the **fee currency** your
contract bills in, and your **settlement currency**. Which pair is used, and how
many conversions happen, depends only on which of the three are equal.

The customer-facing rounding rules, as they apply on a **2-decimal** account, are:

| Rule | Meaning |
| - | - |
| `ROUND2` | Round half up to 2 decimal places |
| `ROUNDUP2` | Round **up** to 2 decimal places |
| `ROUNDDOWN2` | Round **down** to 2 decimal places |

On a **6-decimal** account the fee (and the fixed chargeback and failure fees) is
rounded **half up at 6 decimals** rather than up — the round-up rule exists to
protect a 2-decimal figure from under-collection, and at 6 decimals the residual
is tracked instead. Everywhere the case tables below say `ROUNDUP2`, read
"round half up at 6 decimals" if you are on a 6-decimal account.

### Case A — order = fee = settlement currency

No conversion. `Forex Currency Pair` and `Forex Rate` are empty.

| | Formula |
| - | - |
| `FeeAmount(SettlementCurrency)` | `ROUNDUP2(OrderAmount * feeRate)` |
| `FeeAmount` | `= FeeAmount(SettlementCurrency)` |
| `OrderAmount(SettlementCurrency)` | `= OrderAmount` |
| `PAYMENT` Settlement Amount | `OrderAmount(SettlementCurrency) − FeeAmount(SettlementCurrency) − TaxAmount(SettlementCurrency)` |
| `REFUND` Settlement Amount | `− OrderAmount(SettlementCurrency) − FeeAmount(SettlementCurrency) − TaxAmount(SettlementCurrency)` |
| `CHARGEBACK` Settlement Amount | `− OrderAmount(SettlementCurrency) − FeeAmount(SettlementCurrency)` |

Worked example with an illustrative 2% rate (not a quoted rate), all currencies USD:

| Type | Order Amount | Fee Amount | Settlement Amount |
| - | - | - | - |
| `PAYMENT` | 100.00 | 2.00 = `ROUNDUP(100.00 × 2%, 2)` | 98.00 |
| `REFUND` | 50.00 | 1.00 = `ROUNDUP(50.00 × 2%, 2)` | −51.00 |
| `CHARGEBACK` | 50.00 | 10.00 (as reported for the case) | −60.00 |

### Case B — order = fee currency, different settlement currency

`Forex Currency Pair = SettlementCurrency/OrderCurrency`

| | Formula |
| - | - |
| `FeeAmount(SettlementCurrency)` | `ROUNDUP2(OrderAmount * feeRate / forexRate)` |
| `FeeAmount` | `ROUND2(OrderAmount * feeRate)` |
| `OrderAmount(SettlementCurrency)` | `ROUND2(OrderAmount / forexRate)` |
| `CHARGEBACK` fee conversion | `FeeAmount(SettlementCurrency) = ROUNDUP2(FeeAmount / forexRate)` |

Worked example with an illustrative 2% rate, order and fee in USD, settlement in HKD, pair `HKD/USD` at
`0.12770000`:

| Type | Order Amount | Order Amount (Settlement Currency) | Fee Amount | Fee Amount (Settlement Currency) | Settlement Amount |
| - | - | - | - | - | - |
| `PAYMENT` | 100.00 | 783.09 = `ROUND(100 / 0.1277, 2)` | 2.00 | 15.67 = `ROUNDUP(100 × 2% / 0.1277, 2)` | 767.42 |
| `REFUND` | 50.00 | 391.54 | 1.00 | 7.84 | −399.38 |
| `CHARGEBACK` | 50.00 | 391.54 | 10.00 | 78.31 = `ROUNDUP(10 / 0.1277, 2)` | −469.85 |

### Case C — fee currency differs, order = settlement currency

`Forex Currency Pair = SettlementCurrency/FeeCurrency`

| | Formula |
| - | - |
| `FeeAmount(SettlementCurrency)` | `ROUNDUP2((OrderAmount * forexRate) * feeRate / forexRate)` |
| `FeeAmount` | `ROUND2((OrderAmount * forexRate) * feeRate)` |
| `OrderAmount(SettlementCurrency)` | `= OrderAmount` |

This is the case that surprises people: your order currency equals your
settlement currency, yet `Forex Currency Pair` and `Forex Rate` are populated,
because the **fee** had to be converted. `feeRate` here may also carry a minimum
or a fixed component.

Worked example with an illustrative 2% rate, order and settlement in HKD, fee in USD, pair `HKD/USD` at
`0.12770000`:

| Type | Order Amount | Fee Amount | Fee Amount (Settlement Currency) | Settlement Amount |
| - | - | - | - | - |
| `PAYMENT` | 100.00 | 0.26 = `ROUND(100 × 0.1277 × 2%, 2)` | 2.00 | 98.00 |
| `REFUND` | 50.00 | 0.13 | 1.00 | −51.00 |
| `CHARGEBACK` | 50.00 | 10.00 | 78.31 = `ROUNDUP(10.00 / 0.1277, 2)` | −128.31 |

### Case D — order currency differs, fee = settlement currency

`Forex Currency Pair = SettlementCurrency/OrderCurrency`

| | Formula |
| - | - |
| `FeeAmount(SettlementCurrency)` | `ROUNDUP2(OrderAmount / forexRate * feeRate)` |
| `FeeAmount` | `= FeeAmount(SettlementCurrency)` |
| `OrderAmount(SettlementCurrency)` | `ROUND2(OrderAmount / forexRate)` |
| `CHARGEBACK` fee conversion | none — `FeeAmount(SettlementCurrency) = FeeAmount` |

Worked example with an illustrative 2% rate, order in HKD, fee and settlement in USD, pair `USD/HKD` at
`7.83010000`:

| Type | Order Amount | Order Amount (Settlement Currency) | Fee Amount | Settlement Amount |
| - | - | - | - | - |
| `PAYMENT` | 100.00 | 12.77 = `ROUND(100 / 7.8301, 2)` | 0.26 | 12.51 |
| `REFUND` | 50.00 | 6.39 | 0.13 | −6.52 |
| `CHARGEBACK` | 50.00 | 6.39 | 10.00 | −16.39 |

### Case E — order, fee and settlement currencies are all different

Two pairs are needed: `SettlementCurrency/OrderCurrency` to produce the clearing
amount, and `SettlementCurrency/FeeCurrency` to produce the fee. Neither is
derived from the other:

```
Fee Amount (fee currency)        = round[ (OrderAmount / rateOrder * rateFee) * feeRate ]
Fee Amount (settlement currency) = round[ (OrderAmount / rateOrder * rateFee) * feeRate / rateFee ]
```

Because the fee-currency rate appears in both the numerator and the denominator
of the settlement-currency figure, the **effective fee percentage against your
clearing amount stays equal to your contracted rate** — it is not eroded by the
double conversion. This is worth checking when you reconcile a three-currency
account: divide `Fee Amount (Settlement Currency)` by
`Order Amount (Settlement Currency)` and you should land on your contracted rate,
subject only to rounding.

## Why is my fee different from rate × amount? (minimum and maximum fee)

Your contract may carry a `minFee`, and either a `maxFee` (an absolute cap) or a
`maxFeeRatio` (a percentage cap). **`maxFee` and `maxFeeRatio` never both apply
to the same fee item.** The checks run in a fixed order, and a check that trips
*replaces* the computed fee rather than adjusting it:

1. **`minFee` is checked first.** If the computed fee in the fee currency is
   below `minFee`, both the fee-currency and the settlement-currency figures are
   recomputed from `minFee`, rounding **up**. The recomputation uses the raw
   `minFee` value as its input, not the already-rounded computed fee.
2. **Then the maximum is checked** — whichever of the two your contract carries.
   * `maxFee`: if the computed fee in the fee currency exceeds `maxFee`, both
     figures are recomputed from `maxFee`, rounding **down**.
   * `maxFeeRatio`: if `fee deducted (settlement currency) / clearing amount
     (settlement currency)` exceeds `maxFeeRatio`, both figures are recomputed as
     the order amount times `maxFeeRatio`, rounding **down**.

So a fee that has hit its floor rounds up, and a fee that has hit its ceiling
rounds down. `minFee` is always contracted at 2 decimal places or fewer, so it
needs no rounding of its own when it is applied.

The practical consequence for small-ticket transactions: below a certain order
amount, your fee stops being proportional and becomes flat at `minFee`, and the
effective percentage rises as the ticket falls. This is the single most common
cause of "the fee on this transaction looks wrong".

## What is a Return Fee, and how is it calculated?

A **Return Fee** returns part of the *original payment fee* to you when you
refund. It exists only if your contract includes it — the default is a refund
**without** fee return, covered in
[Refund FAQ](/docs/en/support/refund-faq).

Where it applies, the refund row's settlement amount gains it as a **positive**
component:

```
Settlement Amount = − OrderAmount(SettlementCurrency)
                    − FeeAmount(SettlementCurrency)
                    − TaxAmount(SettlementCurrency)
                    + ReturnFeeAmount(SettlementCurrency)
```

Both figures are pro-rated, and they use **different rounding rules**:

```
ReturnFeeAmount                     = ROUNDDOWN2( RefundOrderAmount / OriginalOrderAmount × OriginalFeeAmount )
ReturnFeeAmount(SettlementCurrency) = ROUND2( ReturnFeeAmount / OriginalFeeAmount × OriginalFeeAmount(SettlementCurrency) )
```

Read the second formula carefully: the settlement-currency return is pro-rated
against the **already-rounded-down** fee-currency return, not recomputed from the
refund ratio. That is what keeps the two figures consistent when the fee was
billed in a third currency.

Worked example with illustrative rates — all currencies USD, payment fee 2%, refund fee 0%,
Return Fee pro-rata:

| Type | Order Amount | Fee Amount | Settlement Amount |
| - | - | - | - |
| `PAYMENT` | 100.00 | 2.00 | 98.00 |
| `REFUND` | 50.00 | **−1.00** = `ROUNDDOWN((50.00 / 100.00) × 2.00, 2)` | **−49.00** = `−50.00 + 1.00` |

Two things to note:

* The refund row's `Fee Amount` is **negative**. That is the Return Fee, not a
  charge — a negative fee on a refund row is expected, not a data error.
* The refund's own fee (`refund fee rate`) and the Return Fee are separate
  contract items. A refund can carry a refund fee *and* return part of the
  payment fee.

Rounding down means the returned amount can land a cent below straight pro-rata
arithmetic. On a full refund the ratio is 1 and the entire original fee comes
back.

## Do I get my VAT back when I refund?

**No.** A refund does not return VAT. In the clearing steps above, the tax step
is simply skipped for a refund transaction — there is no VAT computation on the
reverse leg, so there is nothing to return.

This is separate from the payment fee question: the payment fee *may* come back
if your contract carries a Return Fee, but the tax does not, under any contract
configuration.

## Can the fee currency change, and what can it be?

The fee currency must be **either your settlement currency or the order
currency**, and it **cannot be changed on the same day** — the request is
rejected by validation. This is why the five cases above are exhaustive in
practice for a single transaction.

## My settlement period netted out negative. What happens?

Nothing moves that day, and nothing is written off.

* A settlement is only initiated when the net settlement amount is **greater than
  zero**. A period whose refunds and chargebacks outweigh its payments produces
  no payout and no funds transfer.
* The negative amount **carries forward and accumulates**. It is added to the
  next period, and the next, until the running total turns positive — at which
  point the whole accumulated amount settles as **one** transfer.
* The same rule applies when a chargeback is what pushed the period negative: the
  chargeback is not charged against any other account, it simply waits for later
  transactions.

A worked shape: four consecutive negative settlement dates followed by a positive
one do not produce four transfers and a correction. They produce a single
transfer, for the net of all five, on the day the total turns positive. All five
settlement records point at that one transfer, so you can reconcile the transfer
back to every period it covers.

Because of this, **a missing payout on a settlement date is not necessarily an
error**. See
[Settlement Cycle & Calendar](/docs/en/support/settlement-cycle-faq) for the other
reasons a settlement date can pass without money arriving.

## Why does the batch total not equal the sum of my detail rows?

It should — but only after the correct rounding at the correct level. The summary
is the detail rows summed and rounded **once, at the end**:

```
Summary Settlement Amount = ROUND2( Σ Settlement Amount in the settlement details report )
```

If you round each detail row to 2 decimals first and then add them up, you will
drift from our figure by up to half a cent per row. Sum at full precision, round
last.


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