SkinsharkError for any non-2xx response.
This page covers what to do with that error.
Using @skinshark/sdk
If you’re using the SDK, you get the typed error class plus narrowing
guards out of the box:
Retry-After honoring. POST/PATCH retries are gated on the presence of
idempotencyKey to prevent double-charges. The decision tree below
applies whether you’re using the SDK or raw fetch — the SDK handles the
network/timeout/5xx layer for you, and you handle the business-rule
errors at the call site.
The retry decision tree
Reconcile vs replay
Replay = send the same request again with the sameIdempotency-Key.
The server deduplicates and returns the original result. Only POST /merchant/users/{id}/fund supports this today.
Reconcile = query the API to discover whether the previous attempt
succeeded, regardless of whether you ever saw the response.
When in doubt, reconcile. Replay is only safe on idempotent endpoints.
Bounded retry helper
A reusable retry-with-backoff for safe operations:Common error keys, by category
Auth (don’t retry — fix the credential)
Money (don’t retry — surface to user)
Trade (mostly user-facing)
Idempotency
The full table is in Errors.
Async trade outcomes
The keys above are synchronous — they come straight back from thebuy /
quick-buy call. A trade that was accepted can still fail asynchronously while
the marketplace fulfills it. That outcome arrives via webhook (trade.*) and on
the trade’s terminal status:
On a
failed item, error is one of:
canceled and declined items carry no error code — the status is the
outcome. An optional errorDetail string carries the raw marketplace reason
(e.g. "c5:ITEM_SOLD item already sold") for debugging only — treat it as
opaque and never branch on it.
What to log
Every error has arequestId. Log it on every API call (success or fail)
so support can trace through our side. A useful client-side log line:
requestIds — they
let us pull the full request/response and ledger trace from our side
without back-and-forth.