The header
- The sub-user’s UUID (returned by
POST /merchant/users), or - The
externalIdyou assigned when creating them.
externalId to their internal user ID
(user_42, acme_customer_8129) and never persist the SkinShark UUID.
Where the header applies
| Route prefix | On-Behalf-Of |
|---|---|
/merchant/* | Rejected. Sub-users don’t hold the merchant role, so the call fails with FORBIDDEN. |
/user/* | Optional — sets the calling sub-user. |
/market/* | Optional — sets the calling sub-user. |
/auth/ws-token, /ws | Optional — scopes the WebSocket token. |
@skinshark/sdk, you can either pass onBehalfOf per call or bind a
sub-user once with await sdk.as(ref) and call methods on the returned
client — it injects the header for every call. See the
SDK guide for the full pattern.
Without the header on a sub-user-context route, the call runs as the
merchant itself. That’s intentional: it lets the merchant trade for its
own account when needed.
Examples
- Buy for a sub-user
- Buy for the merchant
- List a sub-user's trades
The buy debits
user_42’s wallet, uses their primary Steam trade URL,
and the resulting trade shows up under their history.Resolving the value
The server resolves both UUID andexternalId against parentId = your merchant. A UUID that belongs to a different merchant returns
USER_NOT_FOUND — never FORBIDDEN — so other merchants’ UUIDs can’t be
enumerated through error responses.
Mistakes to watch for
Sending On-Behalf-Of on a /merchant/* route
Sending On-Behalf-Of on a /merchant/* route
The
requireMerchant guard checks the resolved role. Sub-users don’t
have the merchant role, so the call returns FORBIDDEN with code 1300.
Drop the header for merchant-context routes (or just don’t send it on
that path).Forgetting On-Behalf-Of on /market/buy
Forgetting On-Behalf-Of on /market/buy
The buy succeeds — but it buys for the merchant. If you wanted to buy
for a customer, you’ll see the listing in your merchant trade history,
not theirs, and the merchant’s wallet was debited.Defensive pattern: always set
On-Behalf-Of when handling a customer
request, never derive intent from absence:Letting end users supply the externalId
Letting end users supply the externalId
externalId is a server-side trust boundary. If your client lets a
user pass an arbitrary ID and you forward it as On-Behalf-Of, you’ve
just given that user the ability to act as any of your sub-users.
Always derive the value from your own session/auth, not request input.Suspended sub-users
If a sub-user is suspended (viaPOST /merchant/users/{id}/suspend), every
On-Behalf-Of resolution to that user returns:
POST /merchant/users/{id}/reactivate.