Skip to content
SkanPay Docs

Withdrawals

A withdrawal sends your available balance to one of your own approved payout wallets (cash-out).

MethodPath
POST/v1/withdrawalsCreate a withdrawal
GET/v1/withdrawals/:idRetrieve a withdrawal

To list withdrawals, use GET /v1/transactions?type=WITHDRAWAL; add approval_status=PENDING to see those waiting for a second approver.

The withdrawal object

{
  "id": "wdl_01J9Z6C3D4E5F6G7H8J9K0M1N2",
  "object": "withdrawal",
  "status": "INITIATED",
  "amount": "6000000",
  "currency": "UGX",
  "country": "UG",
  "network": "MTN",
  "destination": "wal_01J9Z3K8Q4W6XK2M7N5P0R3T8V",
  "msisdn_masked": "+2567****111",
  "reference": "sweep-2026-09-28",
  "fee": "7500",
  "total_debited": "6007500",
  "provider": null,
  "approval_status": "PENDING",
  "failure_code": null,
  "failure_message": null,
  "metadata": null,
  "created_at": "2026-09-28T17:00:00.000Z",
  "updated_at": "2026-09-28T17:00:00.000Z"
}

Attributes

idstring
Unique id, prefixed wdl_.
objectstring
Always "withdrawal".
statusenum
INITIATED while waiting for approval; then as in statuses.
amountstring
What your wallet receives, in full.
currencyenum
UGX, KES or GHS.
countryenum
The wallet's country: UG, KE or GH.
networkenum
MTN or AIRTEL.
destinationstring
The payout wallet id (wal_…).
msisdn_maskedstring
The wallet number, masked (+2567****456). Full numbers are never returned.
referencestring
Your reference, unchanged.
feestring
The payout fee, charged on top. Shown from the start (it is the amount held).
total_debitedstring
amount + fee: held when requested, paid out on success, released on failure.
providerstring | null
An identifier for the rail that carried the payment. Informational: don't build logic on it.
approval_statusenum
NOT_REQUIRED, PENDING (waiting for a second team member), APPROVED or REJECTED.
failure_codestring | null
As for other transactions, plus approval_rejected when a team member rejects it.
failure_messagestring | null
Human-readable reason. Don't parse it.
metadataobject | null
As sent.
created_atstring
ISO 8601, UTC.
updated_atstring
ISO 8601, UTC. Changes with the status.

Create a withdrawal

POST/v1/withdrawals

The wallet must be ACTIVE (approved and past its 24-hour cooling-off), and currency must be its country's currency. Above your approval threshold it waits for a second team member. Rate-limited to 60 per minute.

Headers

Idempotency-KeyheaderRequired
8–255 characters. Same key and body returns the original response. See Idempotency.

Body parameters

amountstringRequired
Integer minor units as a string, e.g. "50000". See Amounts.
currencyenumRequired
UGX, KES or GHS. Must be the currency of the wallet's country.
destinationstringRequired
A payout wallet id (wal_…) from GET /v1/payout_destinations.
referencestringRequired
Your own id for this payment, e.g. your order id. 1–128 characters from A–Z a–z 0–9 . _ : -. Returned unchanged everywhere.
narrationstringOptional
Up to 100 characters. Shown to the recipient where the network supports it.
metadataobjectOptional
Up to 20 keys of your own data. Values are strings (≤ 512 characters), numbers, booleans or null.
curl -X POST https://api.skanpay.website/v1/withdrawals \
  -H "Authorization: Bearer $SKANPAY_SECRET_KEY" \
  -H "Idempotency-Key: sweep-2026-09-28" \
  -H "Content-Type: application/json" \
  -d '{"amount":"2500000","currency":"UGX","destination":"wal_01J9Z3K8Q4W6XK2M7N5P0R3T8V","reference":"sweep-2026-09-28"}'

Errors specific to withdrawals: destination_not_found, destination_not_active, insufficient_balance, withdrawals_not_enabled_live.

Retrieve a withdrawal

GET/v1/withdrawals/:id

curl
curl https://api.skanpay.website/v1/withdrawals/wdl_01J9Z6C3D4E5F6G7H8J9K0M1N2 \
  -H "Authorization: Bearer $SKANPAY_SECRET_KEY"

Returns the withdrawal, or 404 withdrawal_not_found.