Multi-merchant / multi-shop
Hierarchy of Merchant → Shop → API Key — when you need to pass `merchantId` / `shopId` on POST /payments and how rate limits / fees roll up.
Every account is structured as Merchant → Shop → API key pair. A merchant is the legal entity that signed the contract; a shop is an operational unit under that merchant (one URL, one brand, one payout config). Each shop has its own apiKey + secretKey pair, scoped to that shop. The vast majority of integrations are single-merchant + single-shop — but the hierarchy exists so SaaS platforms / marketplaces can fan transactions across multiple shops under one merchant, or multiple merchants under one operator account.
The hierarchy
Merchant (MCH-XXX) ← legal entity, KYB on file, settlement payout config
│
├─ Shop A (SHP-XXX) ← brand A, paymentMethodIds[], methodFees{}
│ ├─ pk_test_… / sk_test_… (sandbox keys for Shop A)
│ └─ pk_live_… / sk_live_… (production keys for Shop A)
│
└─ Shop B (SHP-YYY) ← brand B, different methods enabled, different fees
├─ pk_test_… / sk_test_…
└─ pk_live_… / sk_live_…API key scoping
Every API key (apiKey + secretKey pair) belongs to exactly ONE shop. When you authenticate with POST /api/v1/auth/token using a key pair, the resulting Bearer token is scoped to:
- The owning shop — its
paymentMethodIdsdrive whatGET /payment-methodsreturns, and itsmethodFeesdetermine charges. - The owning merchant — listed on
GET /measmerchant.id.
# A typical /me response — single merchant, single shop:
{
"id": "MCH-ON-009",
"name": "Golden Dragon",
"industry": "money_services_business",
"environment": "sandbox",
"capabilities": { … }
}The shopId is implicit in your auth token. You can confirm which shop your key resolved to via the shop field in the response of GET /payment-methods.
Routing a payment to a specific shop
If you use a per-shop key pair (the default), DON'T pass merchantId or shopId on POST /payments — they're inferred from the auth token. The fields exist on the schema as belt-and-suspenders: if you DO pass them, they must match the values resolved from the auth or the call is rejected with forbidden. This protects you from a key from Shop A accidentally charging Shop B.
// All of these work — same result:
// 1. Auth-implicit (recommended):
{ "amount": 50, "paymentMethodId": "1008", "country": "MEX" }
// 2. Explicit, must match auth:
{ "amount": 50, "paymentMethodId": "1008", "country": "MEX",
"merchantId": "MCH-ON-009", "shopId": "SHP-MP1STV8W-832A" }
// 3. Mismatched → 403 forbidden:
{ "amount": 50, "paymentMethodId": "1008", "country": "MEX",
"merchantId": "MCH-OTHER" } // ← rejected, can't charge another merchantRate limits + billing
- Rate limit is per-merchant by default (so a misbehaving shop doesn't starve siblings under the same merchant). See Rate limits.
- Fee structure is per-shop (each shop has its own
methodFees). The shop the key resolved to drives the fee charged on the transaction. - Settlement / payout happens at the merchant level. The merchant's configured wallet receives the aggregated balance across all shops, less platform + processor fees.