Crypto for end users is available to verified merchants only. Unverified merchants receive
ONCHAIN_MERCHANT_NOT_VERIFIED.Supported Networks
All amounts are in USD cents. USDT and USDC are credited 1:1.
Deposits
1
Ask for the user's address
Call
GET /client/crypto/deposit-address?chain=ETH with the client token, or GET /secure/crypto/deposit-address with your API key and a steamId. The first call creates the address. It never changes, so you can cache it and reuse it for every deposit on Ethereum and BNB Smart Chain.2
Show it to the user
Display
address, the network, the accepted tokens and minDepositCents. While status is paused the address is valid but deposits are credited only once the chain resumes.3
The user sends the tokens
AssetPay sees the transfer within seconds and records a deposit with status
pending.4
The deposit clears
After
minConfirmations blocks the deposit becomes completed, your merchant balance is credited, and you receive a crypto_deposit webhook with the steamId. Credit your user when that webhook arrives.Solana addresses are opened on request
A Solana account costs rent while it is open, so it is opened when the user asks for it and closed again once it has been emptied or has sat unused.- Pass
token=USDTortoken=USDC(defaultUSDC) for the token the user is about to send. USDT and USDC use separate accounts behind the sameaddress, and each one is opened on its own. - The first call answers
status: "pending"withaddress: null. Poll the same endpoint with the sametokenevery few seconds until it isactiveandtokenslists that token. This usually takes under a minute. - Call the endpoint again before every later Solana deposit. If the account was closed in the meantime, the call reopens it.
ONCHAIN_ADDRESS_CAPACITY(503) means too many of your users have an open Solana account right now. Retry later.
Minimum deposit
The live value is
minDepositCents in the address response. A deposit under the minimum is recorded with status below_minimum and is not credited. Tell your users the minimum before they send.
Deposit statuses
Cashouts
A cashout debits your merchant balance. Debit your own user before you let it go through. There are two ways to start one, and they differ in who is trusted:The approval call
A cashout requested with a client token starts asawaiting_approval. The amount is already held from your merchant balance, and nothing is sent until your server answers.
AssetPay sends a signed POST to your callback URL, the same URL and the same signature as the skin withdrawal approval:
withdrawal, a skin trade carries trade.
Inside your handler: verify the signature, check that
steamId has at least amountCents on your platform, debit them, then answer 200. If you approve and the payout later ends as failed, rejected or cancelled, give the user their balance back when that webhook arrives.
Fees and amounts
amountCents is what leaves your merchant balance. A flat network fee per chain, feeCents, comes out of that amount, and the user receives receiveCents:
ONCHAIN_WITHDRAW_BELOW_MIN.
Safe retries
requestId is required. Sending the same requestId for the same user returns the first withdrawal and never creates a second one, so a timed out request can be repeated safely. Use a fresh requestId for every new cashout.
Daily limits
Two rolling 24 hour limits apply: one per end user and one for all of your users together. When one is reached the request fails withONCHAIN_CLIENT_WITHDRAW_LIMIT (403):
scope is user or merchant, and remainingCents is what can still be withdrawn now. Cashouts that were refused, failed or cancelled do not count.
Cashout statuses
Webhooks
Both flows report to your regular callback URL with the regular signature. The body has one top-level key that tells you what it is:
The objects are the same ones the list endpoints return, and the event is the object’s
status. awaiting_approval has no webhook of its own: the approval call is that announcement.
Webhooks can arrive more than once. Key your handling on id plus status.