Acting on Behalf of a Sub-merchant
A marketplace's API key has two personalities:
- The marketplace itself — used to call the Connect-management routes (
/api/connect/*). - A specific sub-merchant — used for everything that touches money: payments, payouts, customers, payment links, subscriptions, and so on.
Switching between them is a single HTTP header.
The X-On-Behalf-Of header
X-On-Behalf-Of headerX-On-Behalf-Of: usr_01JABCDEF…Set the value to the subMerchantId you want to act as. The header is case-insensitive; both X-On-Behalf-Of and x-on-behalf-of work.
When a marketplace API key calls a merchant route:
- Without the header → request is rejected with
400 ON_BEHALF_REQUIRED_FOR_MARKETPLACE. Marketplaces have no first-class merchant balance, so there's no sensible default sub-merchant. - With a valid header → the request is treated as if the sub-merchant itself made it. The customer record, the payment's owner, the wallet to credit, and every other side-effect resolve to the sub-merchant.
Non-marketplace API keys (regular merchants, individuals) must not send the header. If they do, the request is rejected with 403 ON_BEHALF_FORBIDDEN_CALLER_TYPE.
Which routes accept the header?
Every standard Inflow merchant API endpoint — payments, hosted checkout, payment links, customers, payment methods, subscriptions, withdrawals, account management, and so on. You don't need to learn a new API surface to operate as a sub-merchant; you just call the same routes you would call as a merchant and add the header.
The only exceptions are the Connect-management routes themselves (/api/connect/*), which always operate on the calling marketplace and do not accept the header.
If you're unsure whether a specific route accepts the header, calling it without the header from a marketplace key is a clean check: you'll either get 400 ON_BEHALF_REQUIRED_FOR_MARKETPLACE (it does, you just need to set it) or normal route behavior (it doesn't).
Validity rules
For a marketplace + X-On-Behalf-Of: <id> request to succeed, all of these must hold:
- The calling marketplace's Connect access is active (not paused, not disabled).
- The target sub-merchant exists and belongs to the calling marketplace — you can't borrow another marketplace's seller.
- The target sub-merchant is operable: KYC is approved and they're not currently suspended.
If any rule fails, the request is rejected before reaching the route handler.
Error codes
All errors come back with a JSON body shaped:
{
"statusCode": 403,
"message": "…",
"errorCode": "…"
}| HTTP | errorCode | When |
|---|---|---|
400 | ON_BEHALF_REQUIRED_FOR_MARKETPLACE | Marketplace caller hit a merchant route without the header. |
403 | ON_BEHALF_FORBIDDEN_CALLER_TYPE | A non-marketplace caller (regular merchant) tried to use the header. |
404 | ON_BEHALF_SUBMERCHANT_NOT_FOUND | The id in the header doesn't correspond to a sub-merchant. |
403 | ON_BEHALF_SUBMERCHANT_NOT_OWNED | The sub-merchant exists but belongs to another marketplace. |
403 | ON_BEHALF_SUBMERCHANT_NOT_OPERABLE | KYC not approved, or the sub-merchant is currently suspended. |
403 | ON_BEHALF_MARKETPLACE_PAUSED | The calling marketplace's Connect access is currently paused. |
403 | ON_BEHALF_CONNECT_DISABLED | Connect is disabled on the calling marketplace. |
The same compliance kill-switches surface on the Connect-management routes too, with shorter codes: 403 MARKETPLACE_PAUSED and 403 CONNECT_DISABLED. See Suspension and Lifecycle.
Examples
Create a payment for usr_seller_42
usr_seller_42curl -X POST https://api.inflowpay.xyz/api/payment/checkout/payment \
-H "Authorization: Bearer $INFLOW_API_KEY" \
-H "X-On-Behalf-Of: usr_seller_42" \
-H "Content-Type: application/json" \
-d '{
"amount": 1500,
"currency": "EUR",
"successUrl": "https://shop.example.com/success",
"cancelUrl": "https://shop.example.com/cancel"
}'List a sub-merchant's customers
curl "https://api.inflowpay.xyz/api/customer?page=1&limit=20" \
-H "Authorization: Bearer $INFLOW_API_KEY" \
-H "X-On-Behalf-Of: usr_seller_42"Trigger a payout for a sub-merchant
curl -X POST https://api.inflowpay.xyz/api/withdraw/... \
-H "Authorization: Bearer $INFLOW_API_KEY" \
-H "X-On-Behalf-Of: usr_seller_42" \
-H "Content-Type: application/json" \
-d '{ "amount": 50000, "currency": "USDC", "destination": "…" }'Webhooks
Inflow's standard webhooks (payment.*, subscription.*, withdraw.*, …) are emitted with the sub-merchant's userId as their owner. If your marketplace listens for them, dispatch by userId to the right seller in your own database — the marketplace userId only appears on marketplace-fee-related events.
Common pitfalls
- Forgetting the header from a marketplace key. You'll get
400 ON_BEHALF_REQUIRED_FOR_MARKETPLACE. The header isn't optional once your account is a marketplace — there's no fallback. - Reusing the marketplace's own user id in the header. Marketplaces are not sub-merchants; the request will fail with
404 ON_BEHALF_SUBMERCHANT_NOT_FOUND. - Acting on a not-yet-approved sub-merchant. Even right after
POST /api/connect/accounts, you'll get403 ON_BEHALF_SUBMERCHANT_NOT_OPERABLEuntil KYC completes. Always checkkycStatus = "approved"first. - Acting on a suspended sub-merchant. Same
403 ON_BEHALF_SUBMERCHANT_NOT_OPERABLE. Resume them first viaPOST …/resume(see Suspension and Lifecycle).
Updated about 19 hours ago