POST /v2/payouts. Hermes holds the money at once.
Hermes then tracks the transfer to a terminal state.
For money that comes into your balance, see Collections.
One endpoint, three destination types
There is no rail in the path. Thetype field of the destination object
selects the rail.
Rules for each type:
institution_idcomes fromGET /v2/institutions?asset=KES. The list is per asset. Each entry tells you itstype. Keep the list in a cache, and read it again if a create request refuses the id.mobile_numberis in E.164 form, with the+. An example is+254712345678. The country code must agree with the asset. Hermes refuses a number in a different form, and never corrects it for you.account_numbermust agree with the digit rule of the destination bank. Hermes does not check the name on a KES bank account. Hermes sendsbeneficiary_nameto the bank and stores it. Nobody compares it with the account.networkisethereum,solana, ortron. The asset must exist on that network. USDT is on the three networks. USDC is onethereumandsolana. A different pair getsinvalid_wallet_address.addressmust have the correct shape for the network. Onethereum, an address in mixed case must pass the EIP-55 checksum. An address in lower case only needs the correct shape.beneficiary_typeisindividualorbusiness. The default isindividual.beneficiary_date_of_birthis necessary for eachindividual, inYYYY-MM-DDform.beneficiary_countryis an ISO-2 code.- Hermes does not support a wallet destination that needs a memo or a tag.
400 or 422, and Hermes makes no payout.
The money fields
amount and asset are always what the beneficiary receives. Hermes
never changes them.
source_asset is the asset that you pay from. The default is asset. When
source_asset is the same as asset, the payout is a same-asset payout.
The response shows source_amount equal to amount, and rate is null.
The FX payout
Whensource_asset is different from asset, the payout is an FX payout.
Hermes converts and pays in one movement. An example is a KES payout that you
pay from USDT.
source_amount— what Hermes debits from yoursource_assetbalance, with the conversion in it. The fee is not in it.fee— the payout fee of Jenzy, insource_asset. One total, not a breakdown.rate—source_amountdivided byamount, at eight decimal places. The rate is for display. The two amounts are the truth.
unsupported_pair (422). The rate is the rate
at the time that Hermes accepts the payout. There is no quote step for a
payout. If you want to see the rate first, use a
conversion quote as a guide.
When Hermes accepts a payout, it holds
source_amount, the fee, and a
reserve for the provider fee, all in source_asset. Your available in
that asset must cover the three together. If it does not, you get
insufficient_funds (402), and Hermes makes no payout.Idempotency
Each create request needs anIdempotency-Key header. A request with no
key gets 400 validation_error. 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 gets 409 conflict. One key group
covers /v1 and /v2. Do not use one key on both APIs.
A payout can be failed in its creation response
Hermes sends the payout to the provider inside the create call. Most refusals
happen before Hermes holds money, and those are a 4xx with no payout. In
rare cases the provider refuses the payout at once. Then the 201 response
carries the payout with status: "failed", and failure set.
Hermes already released the hold. Hermes also sends payout.failed. Read the
status of each 201 response. Do not assume that a 201 is a payout in
progress.
The payout resource
Read payouts withGET /v2/payouts and GET /v2/payouts/{id}.
GET /v2/payouts puts the newest payout first and uses keyset pagination.
Filter with asset and status. The create response and the data field of
each payout webhook use the same shape.
Status lifecycle
held— the money is on hold. The provider did not confirm the payout yet. A payout stays here for a short time, or when the provider is not available. Hermes continues from here by itself.pending— the provider has the payout and works on it. This is the only status where a payout waits. 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.
/v1. The failure.code words are the
same too. The reference also lists received, validated, and submitted.
A /v2 payout passes through them inside the create call. You do not see
them in a response or in an event.
How to learn the result
Webhooks (recommended) — Hermes sendspayout.succeeded, payout.failed,
or (not often) payout.reversed. A /v2 delivery carries
api_version: "v2", and data is the payout in the shape above. See
Webhooks.
A poll — read GET /v2/payouts/{id} again until the status is terminal.
A poll and a webhook give the same data. So you can always use
GET /v2/payouts to catch up after an outage.
When a payout fails, Hermes releases the full hold back to available in
source_asset. A failed payout shows fee: "0". 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.
Limits
Each asset and each destination type has a minimum and a maximum for one payout. Hermes measures the limits onamount, the figure that the
beneficiary receives.
- Below the minimum gets
amount_below_minimum(422). - Above the maximum gets
limit_exceeded(422).
/v2. Your available in source_asset is the
ceiling. The request rate limit of your org still applies. See
Authentication.
Common rejections
Hermes refuses the request and holds nothing. See Errors for the complete list.insufficient_funds(402) —source_amountplus the fee is more than youravailableinsource_asset.corridor_not_enabled(403) — Jenzy did not enable this asset, or this operation in this asset, for your org.unsupported_pair(422) —source_assetandassetare both fiat, or both stablecoins.invalid_wallet_address(422) — the address has the wrong shape for the network, or the asset does not exist on the network.rate_unavailable/service_unavailable(503) — Hermes has no fresh rate for an FX payout, or no rate to price the fee. Send the request again after a short time.amount_below_minimum/limit_exceeded(422) — see Limits above.