@assetpay/assetpay-sdk is the official Node.js client for this API. It wraps every public endpoint with typed methods and takes care of the parts that are easy to get wrong:
- Client tokens are minted and renewed for you.
- Retries never send a money-moving request twice.
- Webhooks are verified and classified, including approval callbacks.
- Events from the Socket.IO endpoint arrive typed, with reconnects handled.
Install
require() on those versions. Its one runtime dependency is undici, the HTTP client that powers Node’s own fetch.
Create a client
apiSecret and merchantId are optional, but with both set the SDK mints client tokens locally instead of calling POST /auth/authenticate-client for every user. Point baseUrl at https://api-staging.assetpay.gg to use staging.
Every withdrawal, including your own
/secure/buy, is sent to your callback URL for approval. Configure a callback URL and an API secret before your first withdrawal, or it fails with MERCHANT_NO_CALLBACK_URL or MERCHANT_NO_API_SECRET.Merchant and end-user calls
The client itself calls the merchant endpoints with your API key.asClient() returns the end-user endpoints for one Steam user, authenticated with a client token.
Tokens are renewed 5 minutes before they expire. If a request comes back
INVALID_TOKEN, for example after you rotate your API secret, the SDK issues a new token and replays the request once.
List endpoints have async iterators that follow the right cursor for you:
Retries and uncertain outcomes
The SDK retries reads through network errors and unexplained server errors. It retries trade-creating calls (sell, buy, quickBuy, deposit, withdraw, quickWithdraw) only when the failure proves nothing was sent. Every call retries the refusals FLEET_DEGRADED, DEPOSIT_IN_PROGRESS, WITHDRAW_IN_PROGRESS and ONCHAIN_CLIENT_WITHDRAW_BUSY, which the API raises before doing any work. Rate limits (429) are never retried.
When a trade-creating call fails after the request may have reached the API, the error has ambiguous: true: the trade may exist. Send an externalId with every trade and turn on reconcile to have the SDK settle it:
externalId. The API refuses a second trade under an externalId it has seen, so the resend can never create two. If the resend does not return a trade, the SDK looks the trade up with GET /secure/trades/{ref} and returns it. Only when no trade exists does the original error reach you. Check the returned trade’s status, which can already be failed.
Errors
Every failure is anAssetPayError carrying the API’s key, code, status, messages, fields, details and requestId, as described in Errors. Branch on key:
Webhooks
Import from@assetpay/assetpay-sdk/webhooks in a service that only receives callbacks. That entry point has no HTTP dependency. Verify against the raw request body:
isCallbackTestrecognises the unsigned test delivery sent when you save a callback URL.event.typeis derived from the body:withdraw.approval,crypto_withdraw.approval,trade,crypto_deposit,crypto_withdraworunknown.event.dedupeKeyis the delivery id for regular events, and the trade or withdrawal id for approvals, whose delivery id changes on every attempt.- A signature, timestamp or body problem throws
AssetPayWebhookErrorwith areason. Answer it with401. - Pass
secret: [newSecret, oldSecret]while you rotate your API secret.
Events over Socket.IO
@assetpay/assetpay-sdk/realtime wraps the WebSocket endpoint. Install socket.io-client next to the SDK and connect with a merchant API key:
connect(): the first market event after every connect is a sync telling you to refetch, because changes made while you were disconnected are not replayed. The feed reconnects on its own, including after the API restarts. Treat these events as a way to keep screens fresh, and use webhooks for anything that moves money.