Wallets and gas
This page is for partners whose customers use ordinary wallets. The customer’s registered wallet signs every transaction and pays its network fee (“gas”) in POL. The Buy walkthrough and Sell walkthrough tell you when each transaction is needed.
Partners that use smart accounts execute prepared transactions through their own wallet infrastructure and arrange network fees or sponsorship themselves. Report the transaction hash of the transaction included in a block through the same transaction API. Do not report a UserOperation identifier, and do not send a UserOperation signature in signedTransaction, which accepts only a serialized signed transaction.
1. Take the prepared transaction
Every blockchain step comes back from Sinbad as a prepared transaction:
Prepared transactions come from a breakdown (escrowTransaction), from POST /v1/trade-breakdowns/{breakdownId}/approval (transactions) and from POST /v1/trades/{tradeId}/actions/{action}/execution (transaction). Use to, data and value unchanged.
2. Build and sign the transaction
Sign an EIP-1559 (type 2) transaction. You choose the nonce, gas limit and fees, and the customer’s wallet pays for them.
- Set
chainId,to,dataandvaluefrom the prepared transaction, and leave the access list empty. - Use the wallet’s next nonce, counting pending transactions: call
eth_getTransactionCountwith thependingtag. - Set
gasLimitandmaxFeePerGasabove 0, and keepmaxPriorityFeePerGasat or belowmaxFeePerGas. Estimate the gas for the call and add a margin.
Before it accepts signed bytes, Sinbad checks that the signer is from and that the chain, destination, calldata and value match the prepared transaction. A mismatch returns 400 VALIDATION_ERROR.
3. Submit the signed transaction
Call POST /v1/transactions with the signed bytes in signedTransaction (hex, at most 16,000 characters) and the preparationId. The Idempotency-Key header is required: 8 to 128 characters from A-Z a-z 0-9 _ -.
Sinbad broadcasts the transaction and tracks it. The answer is 202, with a transaction object (status, transactionHash, confirmations, requiredConfirmations) and a trade that is null until the trade exists. A 202 means tracking has started, not that the step is done.
To broadcast the transaction yourself, send transactionHash instead of signedTransaction. Send exactly one of the two, and use the hash of the transaction that was included in a block. Two responses are normal when you report a hash:
- A hash report for an escrow transaction can return
202withPENDING_CONFIRMATIONbefore a receipt is visible. - A hash report for an action that is unavailable or unconfirmed can return
502 UPSTREAM_ERROR. Retry the same report later, and do not broadcast again.
4. Keep POL in the customer’s wallet
The wallet pays gas in POL for every transaction: approvalReset, approval, createEscrow, markPaid, cancelPrePaid, release, openDispute and mutualResolveDispute.
When you submit signed bytes, Sinbad checks the balance against the transaction’s maximum fee (gasLimit times maxFeePerGas), including pending transactions. If the wallet is short, the call fails before anything is broadcast or recorded with 400 INSUFFICIENT_BALANCE (numeric ID 4001) and details.kind: "NATIVE_GAS". The details include:
Top up at least the shortfall plus a margin, then submit the same signed bytes again. The prepared transaction stays valid until its expiresAt. Because a breakdown lives for only 300 seconds, fund customer wallets in advance and do not wait for this error.
If a SELL wallet is short of USDT, the error has no details.kind: "NATIVE_GAS", because that is a token shortage. A report that sends only transactionHash is not balance-checked.
Sinbad checks the nonce before the balance. If the wallet’s pending nonce no longer equals the one you signed, the call fails with 409 CONFLICT (“Wallet nonce changed”). Read the nonce again, sign again and submit.
5. Track the status
Poll GET /v1/transactions/{preparationId} and use webhooks for the trade itself. Read requiredConfirmations from the response rather than hard-coding a value. The trade can update after the transaction confirms, so read the trade again instead of submitting again.
6. Use one transaction per prepared transaction
Sinbad normally binds one transaction hash to each prepared transaction.
- After a definite failure (
REVERTED,REJECTEDorEXPIRED), request a new prepared transaction only if the action is still needed and permitted. A trade action returns a new prepared transaction on every call. An approval needs a newIdempotency-Key. A failed escrow transaction needs a new breakdown, once the previous breakdown has released the customer’s open trade. - If you reported the wrong hash for an externally sent escrow transaction, report the correct hash for the same prepared transaction with a new
Idempotency-Key. Sinbad accepts the correction only after a confirmed receipt proves that exact checkout. It cannot replace tracking that is already confirmed.
A pending, missing or uncertain receipt is not permission to send another transaction. The first one may still execute.
7. Retry safely
The Idempotency-Key is bound to the preparationId and to a hash of the signed bytes.
- Sending the same bytes with the same key is a safe replay. It returns the current state and never creates a second transaction.
- Sending different bytes with the same key returns
409 CONFLICT. - After Sinbad has accepted a transaction for a prepared transaction, different bytes for it are refused with
409 CONFLICT, even with a new key. Re-sign with different fees only while nothing has been accepted. - A call that failed before acceptance, such as one with
NATIVE_GAS, recorded nothing. Fix the cause and submit again. Reuse the key only with identical signed bytes. If you sign different fields, use a new key. - Sinbad keeps submission-key bindings for 30 days.
The verified escrow hash correction in step 6 is the one exception that needs a fresh key. It never broadcasts another transaction.
8. When you do not know whether a submission reached the chain
If your submit call times out, or the status is BROADCAST_UNKNOWN, assume the transaction may still reach the chain.
- Do not build a second transaction for the same step, and do not create a new breakdown or action.
- Either send the identical request again (same key, same
preparationId, same signed bytes), or callGET /v1/transactions/{preparationId}. Sinbad keeps tracking and re-sends the same signed bytes if needed. - Wait for
PENDING_CONFIRMATION,CONFIRMED,REVERTED,REPLACED,EXPIREDorREJECTED. - If the result is
EXPIRED,REJECTEDorREVERTED, prepare the step again as described in step 6.
Sinbad simulates the call before it broadcasts signed bytes. If the simulation fails, the response is a generic 503 UPSTREAM_ERROR. Check the allowance, the balance and the trade state before you replay the identical bytes. Temporary RPC problems also return 502 or 503: keep the request and retry with backoff. Unresolved external escrow tracking reaches REVIEW_REQUIRED after 24 hours without expiring the breakdown or releasing the customer’s open trade.