POST /payouts/bank or
POST /payouts/momo. Hermes holds the funds at once. Hermes then tracks the
transfer to a terminal state.
For money that comes into your balance, see Pay-ins.
The two rails
There is norail field to set. The endpoint that you call selects the
rail.
The two rails use the same
institution_id from GET /institutions. Each
entry in that list tells you its rail. If you send an institution to the
wrong endpoint, Hermes refuses the request with unknown_institution. Hermes
does not send the money to a different rail. See Quickstart
for the full request body of each rail.
Idempotency
Each create request needs anIdempotency-Key header. Make one key for
each payout that you intend to send. You can use a UUID.
Send the same key with the same body again, and Hermes returns the first
response again, with the same bytes. Because of this, a network timeout or a
second request cannot cause two payments.
The same key with a different body gives 409 conflict. Use a key a second
time only to send the same payout again.
A 202 response means that Hermes decided: the funds are on hold and the
payout is in a queue. A 4xx response means that nothing happened. There
is no payout and there are no funds on hold.
What a payout costs
Jenzy passes payout fees to you at cost and adds no margin. This is the schedule:
The convenience fee applies to each payout, at all amounts. There is no
minimum amount, and Jenzy does not remove the fee for large amounts.
The government levy applies only above 100,000 MWK. At or below that amount,
the levy is zero.
The figures above include VAT, in a rounded form. Hermes rounds each fee line
to the tambala separately. So a fee that you calculate from these rates can be
one tambala different.
POST /fees/quote gives the exact figure.
Example — a payout of 10,000 MWK:
Two rules come from the pass-through fee:
- The create response does not tell you the exact fee in advance. Call
POST /fees/quotewithdirection: "payout"before you send the payout. The quote gives the exact fee and thetotal_debit. Thetotal_debitis the amount plus the fee, and it is the money that leaves your balance. Your beneficiary still gets the fullamount_mwk. UsePOST /fees/quoteas the correct source of the exact figures. The table above is a simple version of your agreed commercial terms. It is not a replacement for the quote. The quote shows VAT as its ownvatline and does not add VAT to each fee line. So compare your figures ontotal_fee, and not line by line. - Hermes knows the fee for certain only after the provider reports it.
The
feefield of a payout isnullwhile the transfer is in progress. Hermes then writes the charge from the provider into the field. Hermes never calculates that charge itself.
When Hermes accepts a payout, it holds the
amount_mwk and the quoted
fee. Your available balance must cover the two together. Your balance can
be less than the amount, or less than the amount plus the fee. In both
conditions, you get insufficient_funds (402).- Hermes charges a fee only on a payout that succeeds. A
failedpayout always showsfee: "0.00". Hermes releases the full hold, the amount and the fee, back to your available balance. - A
reversedpayout keeps its fee, because the payout did succeed before the provider took the money back. - A
nullfee does not mean that the payout is free. It means that Hermes does not know the fee yet. Do not usenullas zero. Do not usenullto decide if a payout is still in progress. Thestatusfield tells you that. - Hermes calculates the hold from the fee schedule. When the payout settles,
Hermes compares the hold with the charge from the provider. Hermes returns
the difference to your available balance. The
feefield always shows the charge that Hermes observed, and never the first quote. So the debit from your balance can be a small amount different from the quote.
The payout resource
Read payouts withGET /payouts and GET /payouts/{id}. GET /payouts puts
the newest payout first and uses keyset pagination. The create response and
the data field of each payout webhook use the same shape.
Status lifecycle
held— the funds are on hold. Hermes did not send the payout to the provider yet.pending— Hermes sent the payout and waits for the result from the provider. This is the only status where a payout waits. A payout can stay here for some time if the provider is slow to confirm. Hermes reads the status again. Hermes does not send the payout a second time.succeeded/failed— terminal. No other status is final.reversed— the payout succeeded, and then the provider took the money back. This is not a failure. Thefailurefield staysnull. Theterminal_atfield keeps the time of the first success, and not the time of the reversal.
terminal_at one time, when the payout first gets to succeeded
or failed. The field then never changes, not even at a later reversal.
How to learn the result
Webhooks (recommended) — an org admin registers an endpoint in the Jenzy portal. Hermes then sendspayout.succeeded, payout.failed, or (not often)
payout.reversed a few seconds after the result. See Webhooks
for the event list and how to verify a signature.
A poll — read GET /payouts/{id} again until the status is terminal. A
poll and a webhook give the same data. So you can always use GET /payouts
to catch up after an outage.
When a payout fails, Hermes releases the full hold, the amount and the fee,
back to your available balance. The failure.code field tells you if a
second payout can succeed:
Hermes never sends a failed payout again. To try again, always create a
new payout with a new
Idempotency-Key. If you use the old key, you
get the first failure again.
Limits
Three limits apply to each payout. The limits do not depend on your balance.- Per-payout maximum — Hermes refuses one payout above the cap with
amount_limit_exceeded(422). - Daily cap — the payout volume of your org in the last 24 hours.
- Velocity — the payout count of your org in the last 1 hour.
org_limit_exceeded (429).
Send the payout again later. Hermes measures the limits on the amount that
you asked to send, and not on the amount plus the fee. See Errors
for the full table.
Common rejections
Hermes refuses the request and holds nothing. See Errors for the complete list.insufficient_funds(402) — the amount plus the fee is more than your available balance.unknown_institution(422) — the rail of this endpoint cannot pay theinstitution_id. ReadGET /institutionsagain.invalid_mobile_number/mobile_number_institution_mismatch(422, momo only) — the number is not in the full international form. Or the number belongs to the other network.invalid_account_number(422, bank only) — the account number is not valid for the destination bank.amount_limit_exceeded(422) — the amount is above the per-payout maximum.rate_limited(429) /org_limit_exceeded(429) — send the request again after the given time.