Mental model
Acting as a sub-user from your single merchant key is one header:When this fits
- You’re building a product on top of SkinShark and reselling to your own users.
- Each user needs their own balance, trade history, and Steam connection.
- You want chargeback / dispute isolation per user.
- You want per-user reporting in the SkinShark dashboard.
Provisioning
Create one sub-user per end customer when they sign up. Use your own internal user ID asexternalId so you never have to persist the
SkinShark UUID.
POST /merchant/users is API-key-auth only. Provisioning happens
server-to-server, never from a dashboard session.Funding pattern
There are two ways to put money in a sub-user’s wallet:(a) Internal transfer from merchant treasury
You hold balance centrally and dispense it as customers need it. Idempotent.(b) Direct deposit from the customer
The customer pays SkinShark directly via Gate Pay / on-ramp / crypto. Run underOn-Behalf-Of so the deposit credits the sub-user.
Buy flow
Always tag with both the sub-user (On-Behalf-Of) and your own checkout
ID (externalId). The first scopes wallet/trade-URL/history. The second
makes retries idempotent and reconciliation trivial.
Reading customer state
| Question | Endpoint |
|---|---|
| What’s this customer’s balance? | GET /merchant/users/{id}/wallet |
| Their trade history? | GET /merchant/users/{id}/trades |
| Their full ledger? | GET /merchant/users/{id}/ledger |
| Cross-customer aggregate? | GET /merchant/stats?from=&to= |
| All recent trades? | GET /merchant/trades?cursor= |
| Top GMV customers this month? | GET /merchant/stats → bySubUser |
On-Behalf-Of
needed because the merchant is reading their own scope. On-Behalf-Of is
for acting as a sub-user (buys, deposits), not reading their data.
Suspension and offboarding
Treasury and fees
Your merchant has two wallets:spot— what you fund customers from, what direct merchant trades debit.earnings— credited at trade settlement when yourmerchantFeeBps0. This is your cut on customer purchases.
GET /merchant/fees. Fee changes are dashboard-only — the
API exposes them read-only so you can render them in your UI without
giving an automated client the power to change them.
Reconciliation pattern
Nightly job, in pseudocode:Common mistakes
Reusing one externalId across customers
Reusing one externalId across customers
externalId is unique per (merchantId, userId) for users and per
(userId, externalId) for trades. Don’t recycle values across
customers — pick something globally unique to your platform.Forgetting On-Behalf-Of on /market/buy
Forgetting On-Behalf-Of on /market/buy
The buy succeeds, but it buys for the merchant, not the customer.
See Acting on behalf of
for the defensive pattern.
Skipping idempotency on /fund
Skipping idempotency on /fund
Network retries that don’t carry the same
Idempotency-Key will
double-fund. The header is required — the API rejects calls without
it — but make sure your retry loop reuses the same key, not a fresh
UUID each attempt.Treating suspension like deletion
Treating suspension like deletion
Suspending a sub-user freezes them; their wallet balance and trade
history are intact. Use
DELETE only when you mean it: it’s
irreversible and requires a zero balance.