Withdrawals
Check your balance and pay out your organization's earnings.
Pay out your organization's earnings to a Telebirr, M-Pesa, or CBE account. The 7%
JamiDev usage fee is cut from the amount you withdraw (not added on top) — you
withdraw amount, the fee (and any government tax) is deducted, and the destination
receives the net.
All money is in ETB minor units (santim): 10000 = 100.00 ETB.
Withdrawals require a production organization with Developer Mode enabled and
approved KYC. The minimum withdrawal is 100.00 ETB (10000 santim). A
rolling-24h cap of 100,000 ETB per organization applies (HTTP 429 past it).
Withdrawals of 10,000 ETB or less are paid out automatically — they come back with
status processing/completed. Larger amounts are held for manual review
(status: 'pending').
Get balance
GET /api/jamidev/balance
Authorization: Bearer jamidev_live_…With the SDK:
const { balanceMinor, eligible } = await jami.getBalance();Response
{ "success": true, "eligible": true, "balanceMinor": 250000, "currency": "ETB" }balanceMinoris your organization's own earnings in santim — what this org has generated and not yet withdrawn. It's the ceiling on what you can withdraw, not the owner's whole Jami wallet.eligibleisfalse(andbalanceMinoris0) when the org isn't in production or Developer Mode is off.
Create a withdrawal
POST /api/jamidev/withdrawals
Authorization: Bearer jamidev_live_…
Idempotency-Key: payout-2026-08-12-001 (optional)
{ "amount": 10000, "gateway": "telebirr", "account": "251911223344" }With the SDK:
const withdrawal = await jami.createWithdrawal({
amount: 10000, // gross santim (100 ETB); the 7% fee is cut from this
gateway: 'telebirr', // 'telebirr' | 'mpesa' | 'cbe'
account: '251911223344',
idempotencyKey: 'payout-2026-08-12-001',
});| Field | Notes |
|---|---|
amount | Gross santim to withdraw. Min 10000 (100 ETB). The fee/tax is cut from this. |
gateway | telebirr | mpesa | cbe |
account | Destination phone for the gateway (2519…) |
Idempotency-Key | Optional header. Reusing a key returns the original withdrawal instead of creating a second one. |
Preview the cut offline before calling — the server resolves your org's real rate and is authoritative:
Jami.computeWithdrawalQuote(10000);
// → { amount: 10000, feeAmount: 700, taxAmount: 0, netAmount: 9300, feeRate: 0.07, taxRate: 0 }Response
{
"_id": "665f1c2ab8d3a2f4e1a9c222",
"status": "completed",
"amount": 10000,
"feeAmount": 700,
"taxAmount": 0,
"netAmount": 9300,
"currency": "ETB",
"gateway": "telebirr",
"account": "251911223344",
"createdAt": "2026-08-12T09:29:58.000Z"
}netAmount(amount − feeAmount − taxAmount) is what actually reaches the account.- Amounts ≤ 10,000 ETB auto-pay —
statuscomes backprocessing/completed. Larger amounts land aspending, are reviewed (reviewing/approved/rejected), then paid out (processing→completed).
Errors
400— amount below your org's earnings is fine, but exceeding them returns insufficient JamiDev balance for this organization.402— the amount is within your org's earnings, but the owner's unified Jami wallet (the actual source of funds) was drawn down elsewhere and can't cover it. Possible even whengetBalancelooked sufficient — handle it.429— the org's rolling-24h 100,000 ETB payout cap was reached.
Get / list withdrawals
GET /api/jamidev/withdrawals?page=1&limit=20&status=completed
GET /api/jamidev/withdrawals/{id}
Authorization: Bearer jamidev_live_…const page = await jami.listWithdrawals({ status: 'completed', limit: 20 });
const one = await jami.getWithdrawal('665f1c2ab8d3a2f4e1a9c222');Track completion with the withdrawal.paid / withdrawal.failed
webhooks, or poll getWithdrawal.
