JamiDev
API Reference

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" }
  • balanceMinor is 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.
  • eligible is false (and balanceMinor is 0) 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',
});
FieldNotes
amountGross santim to withdraw. Min 10000 (100 ETB). The fee/tax is cut from this.
gatewaytelebirr | mpesa | cbe
accountDestination phone for the gateway (2519…)
Idempotency-KeyOptional 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-paystatus comes back processing/completed. Larger amounts land as pending, are reviewed (reviewing / approved / rejected), then paid out (processingcompleted).

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 when getBalance looked 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.

On this page