Skip to content

Withdrawals

POST /v1/vakis/{key}/withdrawals

{
"amount": 5000000,
"currency": "COP",
"bank_account": "ba_01J9Z4M2K7QF3B",
"reason": "Pago proveedor — Ficha 06"
}

202 Accepted:

{
"id": "wd_01J9Z4M2K7QF3B",
"object": "withdrawal",
"state": "requested",
"amount": 5000000,
"currency": "COP",
"bank_account": "ba_01J9Z4M2K7QF3B",
"created_at": "2026-08-17T14:00:00Z"
}

State transitions are reported by webhook. Idempotency-Key will be required here, not optional — a retried request must never produce a second transfer.

It requests a payout. It does not execute one.

Section titled “It requests a payout. It does not execute one.”

This is the design, not a limitation of the first version. Money leaving the platform stays a decision with a human in it above a threshold we choose deliberately. A 202 means “we have your request and it is in the queue”, never “the transfer has left”.

Everything this endpoint will enforce, stated now so it is not a surprise later:

  • The cause’s state must permit withdrawal, and available must actually cover the amount.
  • The destination bank account must be verified: true. An unverified account is a rejection, not a pending transfer — see Bank accounts.
  • Hard idempotency. A retry with the same key returns the original withdrawal.
  • Per-key daily limits, plus an amount ceiling above which a human approves before anything moves.
  • A full audit trail: which key, which client, which source address, when.
  • Where a cause is co-owned, two-party authorisation for a partner-initiated withdrawal — designed in from the start rather than retrofitted after the first disputed payout.

Not the code. The numbers: the daily limit, the human-approval threshold, and who approves. Those are policy decisions, and shipping an endpoint that moves money without them would just relocate the decision into a default value nobody chose.

Until this exists, withdrawals happen through the Vaki dashboard, with their existing minimums, timings and controls.