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

# Can Waffo withdraw my balance automatically, and how do I integrate withdrawals?

> The automatic-withdrawal contract end to end — how it is triggered, what the six statuses mean, what happens when your balance is under the threshold, and how to pause or terminate it — plus the withdrawal notification event, how to tell an API withdrawal from a Portal one, exporting the withdrawal list, and what openingRegion and fundsFrom mean on a withdrawal.

[Withdrawals: exceptions & statuses](/docs/en/support/withdrawal-exceptions-and-status-faq) covers a
withdrawal that went wrong. [Withdrawal & Balance API](/docs/en/support/withdrawal-and-balance-api-faq) is
the endpoint contract. **This page covers the two things neither of those answers**: automating
withdrawals so you stop raising them by hand, and the integration details around a withdrawal —
the notification, the identifiers, the export.

## Can Waffo withdraw my settlement balance automatically?

Yes, through an **automatic withdrawal contract**. One contract is attached to one withdrawal
agreement and one recipient bank account, and it raises withdrawals for you on a rule you agree with
Waffo.

The contract is set up by Waffo and goes through an internal approval before it becomes active. Once
it exists, you see it and control it yourself in the Portal at **Account → Withdraw → Auto
Withdrawal**.

To request one, [contact support](mailto:support@waffo.com) and say which currency, which recipient
account, and which rule you want.

## How is an automatic withdrawal triggered?

Two trigger types exist:

| `triggerType` | Rule |
| - | - |
| `AMOUNT_ONLY` | Checked every day. When your withdrawable balance reaches the threshold, a withdrawal is raised |
| `AMOUNT_WITH_PERIOD` | Checked only on the days the period says. On those days, the threshold still has to be met |

For `AMOUNT_WITH_PERIOD` the period is one of:

| `periodType` | Period configuration | Fires on |
| - | - | - |
| `DAILY` | — | Every day |
| `WEEKLY` | Days of the week, e.g. `1,3` | Monday and Wednesday |
| `MONTHLY` | Days of the month, e.g. `1,15`, or `last`, or `15,last` | The 1st and 15th; the last day of the month; both |

Every contract also carries a **trigger time**, expressed in `UTC+8`. The automation re-checks
through the day and acts on the first check at or after that time; a day-level guard means **at most
one automatic withdrawal per contract per day**, however many times the check runs.

The Portal shows the assembled rule as a readable sentence on the contract row, so you do not have
to reconstruct it from the fields.

## How much does an automatic withdrawal take out?

**Your full withdrawable balance**, not the threshold.

The threshold is the condition, not the amount. If your threshold is met, the contract withdraws
everything that is withdrawable at that moment — the settlement account's available balance less any
amount your reserve arrangement is holding back. It is the same figure the Portal shows you as your
withdrawable amount and the same figure a manual full withdrawal would take.

Why your withdrawable amount can be lower than your account balance is covered in
[Balance & Account History](/docs/en/support/balance-and-account-history-faq).

## What happens on a day when my balance is below the threshold?

**Nothing, and nothing fails.** No withdrawal order is created, no error is raised against your
account, and there is no failed row for you to clean up. The next scheduled check applies the same
rule again.

Two thresholds are applied, and being under either one is enough to skip the day:

| Check | Source |
| - | - |
| The contract's balance threshold | Your automatic withdrawal contract |
| The withdrawal agreement's minimum withdrawal amount | Your withdrawal agreement |

So a contract with a threshold below your agreement's minimum will simply never fire below that
minimum — the agreement floor wins.

## My balance was well above the threshold and no withdrawal happened. Why?

In order of likelihood:

| Cause | What you see | What to do |
| - | - | - |
| A previous automatic withdrawal on the same agreement has not reached a final status | No new order | Wait for the open one to finish; the next check picks up |
| One was already raised today | One order, not two | Expected — one per contract per day |
| The trigger time has not passed yet in `UTC+8` | No order yet | Wait for the trigger time |
| The contract is `SUSPENDED`, or outside its effective window | Status on the contract row | Resume it, or ask support about the window |
| The recipient bank account is no longer valid | No order | Contact support — this needs a Waffo-side fix |
| It is not a trigger day for an `AMOUNT_WITH_PERIOD` contract | No order | Check the trigger rule on the row |

The in-flight rule is per **(merchant, withdrawal agreement)** pair: a contract on one currency is
not blocked by an open withdrawal on another.

## What do the automatic withdrawal statuses mean?

| `status` | Meaning | Can it fire? | Can it be edited? |
| - | - | - | - |
| `INIT` | Drafted, not submitted for approval | No | Yes |
| `AUDITING` | Submitted, waiting for approval | No | No |
| `ACTIVE` | Approved and in effect | Yes | Yes |
| `REJECTED` | Approval was refused. Final | No | No |
| `SUSPENDED` | Paused. Can be resumed | No | Yes |
| `TERMINATED` | Ended. Final and irreversible | No | No |

`REJECTED` and `TERMINATED` are terminal: no further action of any kind is possible on that contract,
and its fields are kept only as a record.

## My contract was rejected. Can I fix it and resubmit?

No — a `REJECTED` contract cannot be edited or resubmitted. A rejected rule has to be replaced by a
new contract, which goes through approval again. [Contact support](mailto:support@waffo.com) with
what you want changed rather than trying to reuse the rejected one.

## What is the difference between pausing and terminating?

| | Pause | Terminate |
| - | - | - |
| Status it sets | `SUSPENDED` | `TERMINATED` |
| Reversible | Yes — Resume returns it to `ACTIVE` | **No** |
| Approval needed to undo | None | A new contract, with a new approval |
| Use it when | You want to hold withdrawals for a while — a bank change, a quiet period, an investigation | The arrangement is over |

Both are yours to do, from the contract row in the Portal. Pause is the safe default: if you are not
certain the arrangement is finished, pause rather than terminate.

## Can I have different automatic withdrawal settings per currency?

Yes. A contract is bound to one withdrawal agreement, and a withdrawal agreement is bound to one
withdrawal currency pair, so per-currency rules are the normal shape: one contract per currency, each
with its own threshold, period, trigger time and recipient account.

Contracts are independent of each other, including the in-flight rule described above.

## Is there a notification when a withdrawal finishes?

Yes. Withdrawals send a notification of type **`WITHDRAW_NOTIFICATION`** to the `notifyUrl` you
supply, when the withdrawal succeeds or fails.

| Point | Detail |
| - | - |
| Event name | `WITHDRAW_NOTIFICATION` |
| Where the URL comes from | `notifyUrl` on the withdrawal create request — it is **required** |
| Envelope and signature | The same envelope and `X-SIGNATURE` verification as every other Waffo notification, see [Webhook overview](/docs/en/developer-docs/webhook/overview) |
| Body | The same structure as the withdrawal inquiry response |

Because `notifyUrl` is per request, there is no account-level withdrawal notification setting to
configure: each withdrawal you create carries its own destination. Withdrawals raised in the Portal
and by an automatic contract are not API calls of yours, so treat the notification as a
confirmation channel for withdrawals you created through `/api/v1/withdraw/create`, and the Portal
list as the record for the rest.

Verify the signature and then re-read state from `/api/v1/withdraw/inquiry` before acting on it —
the same rule that applies to payment notifications.

## What is in the withdrawal notification and the withdrawal inquiry response?

One structure serves both:

| Field | Meaning |
| - | - |
| `withdrawRequestId` | Your own identifier for the request |
| `withdrawOrderId` | Waffo's identifier for the withdrawal |
| `status` | Where the withdrawal has reached |
| `currency` | The currency withdrawn from your settlement account |
| `beforeAvailableBalance`, `afterAvailableBalance` | Your available balance either side of the withdrawal |
| `receiveCurrency` | The currency credited to your bank account |
| `expectedReceiveAmount` | What the withdrawal was expected to deliver |
| `actualReceiveAmount` | What it actually delivered |
| `fxRate` | The rate applied, on a cross-currency withdrawal |
| `feeCurrency`, `feeAmount` | The withdrawal fee and its currency |
| `bankRefId` | The bank's own reference — **this is the field to reconcile against your bank statement** |
| `withdrawRequestedAt`, `withdrawCompleteTime` | When you asked, and when it completed |
| `failureCode`, `failureReason` | Populated when the withdrawal failed |
| `merchantBankAccount` | The recipient account used |
| `description` | The description you sent |

`expectedReceiveAmount` and `actualReceiveAmount` differing on a cross-currency withdrawal is normal
and is explained in
[Withdrawals: exceptions & statuses](/docs/en/support/withdrawal-exceptions-and-status-faq).

## Can I tell an API-initiated withdrawal from one raised in the Portal?

Not from a column — the Portal withdrawal list does not show how a withdrawal was started. What
distinguishes them is the request identifier:

| Raised by | Identified by |
| - | - |
| Your API call | The `withdrawRequestId` you sent, returned on `/api/v1/withdraw/inquiry` |
| You in the Portal | A Waffo-generated request identifier |
| An automatic contract | A generated request identifier that encodes the contract and the date |

In practice, if you need the origin as data, keep your own `withdrawRequestId` values and treat
anything you do not recognise as raised outside your integration.

## Can I export my withdrawal list?

Yes — Portal → Account → Withdraw has an Export action. The **export date range cannot exceed 31
days**, so a longer period has to be pulled in several exports.

Like the other Portal exports it is a background task: the file appears in the export history rather
than downloading straight away. See [Export Center](/docs/en/support/export-center-faq).

## Is there a minimum and a maximum withdrawal amount?

Yes — both live on your **withdrawal agreement**, per withdrawal currency pair, and both are enforced
when the withdrawal is created, whether you raise it in the Portal, through the API, or through an
automatic contract. An amount outside the range is rejected at creation rather than failing later.

The values that apply to you are the ones on your agreement; ask support if you do not have them to
hand. The same minimum is the floor the automatic contract respects.

## Which bank account does a withdrawal go to, and how do I add or change one?

Each withdrawal agreement has one or more recipient bank accounts bound to it. When you withdraw:

* the Portal shows you the bound accounts and lets you pick one where more than one exists
* `/api/v1/withdraw/create` takes `bankAccountId`; **leave it out and the agreement's default account
  is used**

Adding or changing an account is **not self-service**. Portal → Settings → Bank Accounts is a
read-only view of the accounts already bound to you — currency, account details, SWIFT code, bank
address. There is no add or edit action, because a new payout destination is a compliance change on
Waffo's side, not a settings change on yours.

To add or change one, [contact support](mailto:support@waffo.com). Have ready the account currency,
the account name and number, the bank name and SWIFT code, the bank address and branch, and the
correspondent bank details where the account needs one — those are exactly the fields the account
record holds.

## What do `openingRegion` and `fundsFrom` mean on a withdrawal, and do they limit how much I can withdraw?

They describe **which side sends the money**, not how much you can take.

| Field | Values | Meaning |
| - | - | - |
| `openingRegion` | `HKG`, `OTHER` | Where your recipient bank account is held |
| `fundsFrom` | Derived from `openingRegion` | Which of Waffo's remitting arrangements is used to pay it |

`fundsFrom` is not something you set: it follows from your account's `openingRegion`. In the Portal
it is what drives the paying entity shown in the **From** block of the withdrawal drawer, so that the
name on your bank statement matches what you were shown before you confirmed.

Neither field caps your withdrawable amount. The amount is governed by your withdrawable balance and
your agreement's minimum and maximum — see the two questions above.

***

Something in your withdrawal does not match this page?
[Contact support](mailto:support@waffo.com) with the withdrawal order id — it identifies the
agreement, the recipient account and the contract behind it in one lookup.


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