curl -X POST \
"https://api.khaime.com/api/v1/merchants/1676/payouts/marketplace_payout_request_1780912800000_1676/approve" \
-H "X-API-Key: pk_live_your_key"
Marketplace
Approve Merchant Payout
Approve a staged sub-merchant payout request.
POST
/
merchants
/
{merchantId}
/
payouts
/
{reference}
/
approve
curl -X POST \
"https://api.khaime.com/api/v1/merchants/1676/payouts/marketplace_payout_request_1780912800000_1676/approve" \
-H "X-API-Key: pk_live_your_key"
Intro
Approves a staged payout request a sub-merchant created with Initiate Merchant Payout, moving it from a marketplace-level request to a real wallet withdrawal queued for Khaime’s own settlement review. In sandbox there is no settlement queue, so the payout finishes here instead — see Sandbox settlement.Context
This is the marketplace operator’s checkpoint in the payout flow:initiate (merchant) → approve (you) → reject (you, alternatively) → Khaime admin settlement. Call it with your marketplace operator Partner API key — the key’s environment (sandbox or live) determines which payout requests you can see and approve. Use List Payout Requests to find pending requests and their reference values first.
Hows
Path parameters
number
required
The business ID of the sub-merchant whose payout should be approved.
string
required
The payout reference returned by Initiate Merchant Payout.
No request body. You can’t change the amount, currency, payout method, or gateway during approval — those were fixed when the merchant initiated the request. Approving also doesn’t contact the payment gateway; that happens at Khaime’s settlement step.
Response
{
"success": true,
"message": "Sub-merchant payout approved. Awaiting Khaime admin settlement.",
"data": {
"payout_request_id": 9821,
"withdrawal_id": 1104,
"merchant_id": 1676,
"reference": "marketplace_payout_request_1780912800000_1676",
"amount": 50000,
"currency": "NGN",
"request_status": "approved",
"withdrawal_status": "payout_pending",
"payment_gateway": "gravv",
"payout_method": "transfer",
"approved_at": "2026-06-08T10:00:00.000Z",
"settled_at": null,
"failure_reason": null,
"sandbox_settlement": null
}
}
| Field | Type | Description |
|---|---|---|
payout_request_id | number | Staged marketplace request ID |
withdrawal_id | number | Wallet transaction ID created for the payout |
merchant_id | number | Sub-merchant business ID |
reference | string | Unique payout reference |
amount | number | Payout amount, smallest currency unit |
currency | string | Payout currency |
request_status | string | Marketplace request status — approved |
withdrawal_status | string | Wallet withdrawal status — payout_pending in live; completed or failed in sandbox |
payment_gateway | string | Gateway selected when the payout was initiated |
payout_method | string | Settlement method — transfer or payout |
approved_at | string | ISO timestamp of your approval |
settled_at | string | null | When the payout settled. Null in live until Khaime settles it |
failure_reason | string | null | Why settlement failed, when it did |
sandbox_settlement | object | null | Present only for a simulated sandbox settlement |
payout_pending wallet withdrawal; the reference stays useful afterward for tracking through Khaime’s admin settlement.
Sandbox settlement
A live payout waits for Khaime to settle it, which can take hours. Sandbox has no such queue, so the payout settles the moment you approve it — the same way a complete KYC submission is approved without waiting for a reviewer. No money moves and no payment gateway is contacted.{
"success": true,
"message": "Sub-merchant payout approved and settled in sandbox.",
"data": {
"reference": "marketplace_payout_request_1780912800000_1676",
"request_status": "approved",
"withdrawal_status": "completed",
"settled_at": "2026-06-08T10:00:00.004Z",
"failure_reason": null,
"sandbox_settlement": {
"simulated": true,
"outcome": "completed",
"settled_at": "2026-06-08T10:00:00.004Z"
}
}
}
settlement.initiated when the payout is requested, then settlement.completed on approval.
Testing a failed settlement
Request a payout whose amount ends in13 — 1013, 25013, and so on, in the smallest currency unit. It settles as failed, settlement.failed fires with a failure_reason, and the sub-merchant’s sandbox balance is restored, because a failed payout is excluded from the balance.
{
"success": true,
"message": "Sub-merchant payout approved, and sandbox settlement failed as requested by the amount.",
"data": {
"withdrawal_status": "failed",
"settled_at": "2026-06-08T10:04:11.793Z",
"failure_reason": "Simulated sandbox settlement failure (amount ends in 13).",
"sandbox_settlement": {
"simulated": true,
"outcome": "failed",
"settled_at": "2026-06-08T10:04:11.793Z",
"failure_reason": "Simulated sandbox settlement failure (amount ends in 13)."
}
}
}
The staged request stays
approved either way — request_status records your decision, withdrawal_status records what happened to the money. A failed sandbox settlement is not a rejected request.Requirements
- Your API key must belong to the marketplace operator associated with the merchant.
- The merchant must have an active relationship with your marketplace.
- The request must have been created through the marketplace Partner API.
- The API key’s environment must match the request’s environment (sandbox/live).
- The request must currently be
pending— the first approval wins if two calls race. - Enough balance must still be available at approval time — a merchant’s balance can shrink between requesting and approval (e.g. a refund lands), so this is re-checked, not assumed from the initial request.
Error cases
| Status | Error | Fix |
|---|---|---|
400 | Payout request amount is invalid. | Underlying data issue on the request — contact support |
400 | Insufficient available balance. Available: X, Requested: Y | The merchant’s balance has since dropped below the requested amount |
401 | Missing or invalid X-API-Key header | Include a valid Partner API key |
403 | This endpoint is restricted to marketplace operators | Your API key must belong to a marketplace operator account |
403 | This payout request does not belong to the authenticated marketplace. | The reference belongs to a different marketplace |
404 | Active merchant relationship not found | The merchant is not linked to your marketplace |
404 | Marketplace payout request not found. | The merchant, environment, or reference don’t match an existing request |
409 | This payout request cannot be approved from status "<status>". | The request is no longer pending — already approved, rejected, or claimed by a concurrent call |
curl -X POST \
"https://api.khaime.com/api/v1/merchants/1676/payouts/marketplace_payout_request_1780912800000_1676/approve" \
-H "X-API-Key: pk_live_your_key"
Whys
Approval creates a withdrawal but doesn’t settle it. Marketplace operators can vouch that a payout is legitimate, but final settlement — the step that actually moves money through a payment gateway — stays under Khaime’s own review. This two-tier approval (operator, then Khaime admin) keeps marketplace operators able to manage their own merchants’ payouts without giving any single operator direct control over gateway-level fund movement. Sandbox settles itself. The admin review exists to protect real money, and sandbox holds none. Leaving sandbox payouts in the same queue meant they pended forever andsettlement.completed never arrived, so an integration could not be driven end to end without a human. Sandbox now finishes the payout on approval, and the amount-ending-in-13 rule gives you the failure branch on demand, the way a test card number does for payments.
Balance is re-checked at approval, not just at request time. Time passes between a merchant requesting a payout and an operator approving it — refunds, chargebacks, or other debits can land in between. Re-validating balance at approval prevents approving a payout the merchant can no longer actually cover.
No request body on approval. Letting an operator change the amount or destination at approval time would mean the merchant never actually agreed to what gets paid out — the terms are locked in at initiation, and approval is strictly a yes/no gate.
Why nots
- Doesn’t settle funds in live. Approval only gets the request in front of Khaime’s own admin settlement — don’t treat “approved” as “paid.” In sandbox it does settle, so don’t read a sandbox
completedas proof that live will be instant. - Can’t be partially approved. It’s the full requested amount or nothing; there’s no mechanism to approve a lower amount than requested.
- Not reversible by re-calling this endpoint. Once a request is
approved, calling approve again on the same reference fails with a conflict — use your own internal process (and Khaime support, if needed) to handle a mistaken approval.
