Before you start
-
A sandbox API key exported as
PLATFORM_API_KEY. See Set up your account. -
A test sender: a Solana keypair holding devnet USDC and no SOL. Get devnet USDC from Circle’s faucet. Export the base58 secret key as
SENDER_SECRET_KEY. Use a key you made for testing only. The sender must already hold the token. A quote for an address that has never held USDC returns400 invalid_requestwith “sender has no token account for this asset”. - A recipient address on devnet.
-
Node.js 20 or later, with
@solana/web3.js,tweetnacl, andbs58installed.
1
Request a quote
Create sponsored transfer takes the chain, asset, sender, recipient, and amount. It requires an The recipient gets
Idempotency-Key. Use one per transfer, so a retry returns the same quote instead of creating a second one.1 and the sender is debited 1.004. The fee here is an example: use the one in your quote. Before going on, check that sign.scheme is solana_ed25519.2
Show the user what they're signing
In a real app, show
recipient_amount, fee, total_debit, and the recipient before you ask for a signature, and get the user’s confirmation. Request the quote when they’re ready to confirm: it expires at expires_at, about three minutes later.3
Sign the message
Decode In production the user’s wallet does this step. Test your wallet integration in sandbox first: it must sign the bytes exactly as given, without adding a prefix.
message_base64 and sign the raw bytes with the sender’s key. Don’t change or hash the message first.sign.mjs
4
Submit the signature
Submit signatures takes the base58 signature as A
signature. It also requires an Idempotency-Key.202 means Bitnob verified the signature, added its own, and queued the transfer for broadcast. A 422 signature_invalid means the signature didn’t match. The quote is still valid, so sign again and resubmit.5
Track it to completed
Poll Get sponsored transfer until the status is terminal.The status moves from
validating to submitted to pending, and then to completed. Once it’s pending, tx_hash is set and you can look the transaction up on a devnet explorer. The sender’s SOL balance is still zero.Put it together
transfer.mjs
pending, and stop at a terminal status.
Next steps
- Send on EVM chains, which need two signatures: Sign on EVM chains.
- Send USDT on Tron, with the one-time approval: Sign on Tron.
- Handle expiry, budgets, and on-chain failures: Handle failures and expiry.