What a seller is
A marketplace app sells on behalf of other people. A seller is a record your app owns: registered, paid and managed entirely with your own API key, with a wallet of its own. A payment for a seller is simply a payment whose money lands in that seller’s wallet.
- No login, no API keys, no dashboard. A seller never signs in to NyukiAI; show them their sales and balance in your own product, read from this API.
- A wallet of their own — pending, available and held, like yours. The payout delay, disputes, refunds and payouts work on it exactly as they do on your own money.
Register a seller
POST /v1/sellers with a name. externalRef is your own id for the seller and is unique per environment: registering the same one twice answers 409 rather than opening a second wallet. Send the payout number in the same call or add it later, and leave commissionBps out to use your app’s default.
{
"id": "sel_01JAY4M8QX2T6N9ZB3KF7RC5WD",
"object": "seller",
"name": "Amina Fabrics",
"email": "amina@example.com",
"phone": null,
"externalRef": "shop-42",
"status": "ACTIVE",
"commissionBps": 500,
"balances": [],
"stats": {
"salesCount": 0,
"gross": "0",
"refunded": "0",
"commission": "0",
"openDisputes": 0
},
"metadata": null,
"created": 1785869000000,
"payoutDestinations": [
{
"id": "pd_01JAY4M8R1C3V7XQ2N6TB9KF4H",
"object": "payout_destination",
"method": "MOBILE_MONEY",
"currency": "XAF",
"country": "CM",
"label": null,
"accountHolderName": "Amina Njoya",
"lastFour": "3456",
"isDefault": true,
"usableFrom": 1785869000000,
"created": 1785869000000
}
]
}Take a payment for a seller
Name the seller with seller, on a payment or on a payment link. On a payment, commissionBps sets the rate for that one sale. The payment and every payment_intent.* event carry seller and the commissionBps that applies, and the hosted checkout tells the buyer which seller they are paying.
How commission is worked out
Your cut of a seller’s sale, in basis points: 250 is 2.5%, and every rate is a whole number from 0 to 10,000. The first of these that is set wins:
- commissionBps on the payment itself.
- The seller’s own commissionBps.
- Your app’s default, set on the Sellers page of the dashboard — 0 until somebody sets it.
- It comes out of the seller’s share. It is never added to what the buyer pays and never taken from NyukiAI’s fee.
- It is worked out on what the buyer paid for the goods. When the buyer bears the processing fee, that surcharge carries no commission.
- It is rounded down, so the fraction of a franc stays with the seller. It is credited to your default wallet and waits out the payout delay like the sale it came from.
- On a refund, your commission on the refunded part goes back to the seller in the same transaction, from the wallet that received it.
Read a seller’s balance
GET /v1/sellers/:id returns the seller with a balance per currency, their sales figures and their payout destinations. GET /v1/sellers lists them, newest first, filterable by status and search, with the same figures. Amounts are strings of minor units.
{
"id": "sel_01JAY4M8QX2T6N9ZB3KF7RC5WD",
"object": "seller",
"status": "ACTIVE",
"commissionBps": 500,
"balances": [
{
"currency": "XAF",
"available": "41200", // the only figure a payout may draw on
"pending": "13800", // captured, still inside the payout delay
"held": "0" // set aside for open disputes
}
],
"stats": {
"salesCount": 4,
"gross": "60000",
"refunded": "0",
"commission": "3000",
"openDisputes": 0
},
"payoutDestinations": [ … ],
…
}Set where a seller is paid
POST /v1/sellers/:id/payout_destinations sets the mobile-money number a seller is paid on. It becomes their default at once, replacing the previous one — there is nobody on the seller’s side to press “make default”. The number is stored encrypted and only its last four digits ever come back. You know your sellers, so a destination you register is trusted as given: no operator reviews it.
{
"id": "pd_01JAY5B2N7W4K8QX3TM6RC9VZD",
"object": "payout_destination",
"method": "MOBILE_MONEY",
"currency": "XAF",
"country": "CM",
"label": "Orange Money",
"accountHolderName": "Amina Njoya",
"lastFour": "2233",
"isDefault": true,
"usableFrom": 1785955400000, // live mode may hold a new number back
"created": 1785869000000
}Pay a seller out
POST /v1/sellers/:id/payouts sends money from the seller’s available balance to their default destination, or to the pd_… you name. The amount leaves the balance at once; the transfer follows, and payout.paid or payout.failed tells you how it ended.
{
"id": "po_01JAY5C9T2M6X8QN4KB7RF3VWD",
"object": "payout",
"seller": "sel_01JAY4M8QX2T6N9ZB3KF7RC5WD",
"status": "REQUESTED", // or AWAITING_APPROVAL above the threshold
"amount": "40000",
"currency": "XAF",
"method": "MOBILE_MONEY",
"destination": "pd_01JAY4M8R1C3V7XQ2N6TB9KF4H",
"destinationLastFour": "3456",
"failureCode": null,
"failureMessage": null,
"paidAt": null,
"created": 1785869000000
}- The money can only go to that seller’s own destination — never to yours, and never to another seller’s.
- A large payout waits for a NyukiAI operator’s approval. The response then says AWAITING_APPROVAL. Nothing is wrong: payout.paid follows once it is released and sent.
- Your app’s payout limit is counted per payee: each seller’s withdrawals count against that seller’s own window, and your own payouts are unaffected by theirs.
- Open disputes count per seller: a seller’s payout is weighed against that seller’s own open disputes, while your own payouts answer for everything open across the account.
- A refusal answers 409 and its message says why: not enough available balance, no usable destination, a suspended seller, payouts paused or blocked, or a limit reached.
Seller statuses
Set with PATCH /v1/sellers/:id. A status decides what may happen next; it never moves money by itself.
| status | Meaning | Payments | Payouts |
|---|---|---|---|
| ACTIVE | Takes payments and is paid out. | Yes | Yes |
| SUSPENDED | You are holding everything: no new payments and no payouts. The balance stays where it is. | No | No |
| CLOSED | Gone from your marketplace. No new payments, but what is left in the wallet can still be paid out. | No | Yes |
Webhooks
payment_intent.* events carry seller (the sel_… id, or null) and commissionBps; charge.* events carry seller and commission, the amount actually kept, so you can credit the right shop from the event alone. payout.paid and payout.failed announce how a payout ended and name the seller — null for your app’s own payout. dispute.* events name the seller of the disputed sale.
{
"id": "wd_01JAY7D4K2N8Q6XT3MB9RF5VWC",
"object": "event",
"type": "payout.paid",
"created": 1785869600,
"environment": "LIVE",
"data": {
"object": {
"id": "po_01JAY5C9T2M6X8QN4KB7RF3VWD",
"object": "payout",
"seller": "sel_01JAY4M8QX2T6N9ZB3KF7RC5WD", // null for your own payout
"status": "PAID",
"amount": "40000",
"currency": "XAF",
"method": "MOBILE_MONEY",
"destination": "pd_01JAY4M8R1C3V7XQ2N6TB9KF4H",
"destinationLastFour": "3456",
"failureCode": null,
"failureMessage": null,
"paidAt": 1785869600000,
"created": 1785869000000
}
}
}On your own Y-Note keys
If your app collects on its own Y-Note account rather than NyukiAI’s, the money goes straight into that account and NyukiAI holds none of it. The payment still records which seller it was for, and the sales figures still count it.
What is not there
So you do not design around something that does not exist:
- A seller portal. Sellers see their money in your product, which reads it from this API.
- Scheduled payouts. Every seller payout is requested by your server.
- Moving money between sellers, or from your app to a seller, other than through commission.
- Deleting a seller. CLOSED is the end state.
- Filtering payment links by seller. A link reports its seller, but no list can be narrowed to one.
- A dispute on a seller’s sale holds the full disputed amount from the seller’s available balance, although they received the sale less fee and commission. That can take their available balance below zero until the dispute is decided.
