Skip to main content
POST
Create a mobile money payout

Authorizations

Authorization
string
header
required

Your Jenzy API key: Authorization: Bearer jz_live_…

Headers

Idempotency-Key
string
required

Required. A key you mint per payout intent (a UUID works). Replays of the same key + body return the original response byte-for-byte; the same key with a different body is a 409.

Body

application/json
amount_mwk
required

Amount in MWK. Either a JSON integer of whole kwacha, or an exact decimal string with up to 2 decimal places ("100000.05"). Fractional JSON numbers are rejected — send a string. More than 2 decimal places is rejected: the tambala is the atom.

Example:

250000

institution_id
integer
required

From GET /institutions — one whose rail is momo.

Example:

112400

mobile_number
string
required

The wallet number in full international form: 265 then 9 (Airtel Money) or 8 (TNM Mpamba) then 8 digits. Sent to the provider exactly as given — a number missing the country code is rejected, never corrected.

Minimum string length: 1
Pattern: ^265[89][0-9]{8}$
Example:

"265991234567"

beneficiary_name
string
required

Who the money is for — required, and sent to the provider as given.

Minimum string length: 1

Response

Accepted: funds are held and the payout is queued for submission. Track it via webhooks or GET /payouts/{id}.

id
string<uuid>
required

Payout id — your handle for polling and support.

amount_mwk
string
required

The amount instructed — exact decimal string at 2 decimal places.

Example:

"250000.00"

fee
string | null
required

What the provider charged for this payout, passed through to you at cost — an exact decimal string at two decimal places (fees are not whole kwacha), so parse it with a decimal library and never a float.

null means the fee is not known — usually because the payout is still in flight, but a terminal payout can also read null when the provider reported no fee for it. It never means free, so do not treat null as zero, and do not treat it as proof the payout is still moving — status is what tells you that.

A failed payout reads "0.00" — fees apply to successful transfers only — and a reversed payout keeps the fee it was charged, because it did succeed before it was clawed back.

Use POST /fees/quote to know the cost BEFORE you send: this field cannot tell you in advance, and your balance must cover the amount plus the fee.

Example:

"2710.00"

rail
enum<string>
required
Available options:
bank,
momo
status
enum<string>
required

Lifecycle: received → validated → held → submitted → pending → succeeded | failed. succeeded, failed and reversed are terminal. reversed means the payout succeeded and the provider then clawed the transfer back — it is not a failure and carries no failure object.

Available options:
received,
validated,
held,
submitted,
pending,
succeeded,
failed,
reversed
Example:

"succeeded"

destination
object
required

The destination snapshot as validated at accept — shape follows rail.

failure
object | null
required

Set exactly when status is failed; null otherwise.

created_at
string<date-time>
required
terminal_at
string<date-time> | null
required

When the payout first reached a terminal state. A payout that is later reversed keeps the timestamp of its original settlement — this never moves once set.