Skip to navigation

Offers and breakdowns

An offer is a merchant’s executable terms for a trade. A breakdown is Sinbad’s priced, time-limited quote for one offer, and it carries the prepared transaction that funds the trade. A breakdown saves the terms but does not create a trade: a trade exists only after funding is confirmed on chain.

Find matching offers

Call POST /v1/offers/best with the customer’s side (BUY or SELL), the token, the fiat currency, an amount and the catalog payment method. The amount has a mode and a value:

  • With mode: "FIAT", value is the market value of the token in the selected fiat currency, before merchant margin and fees. Sinbad converts it to USDT at the current market rate, rounded down to six decimals. The final fiat payment includes merchant pricing and fees, so it can differ from the amount entered.
  • With mode: "USDT", value is an exact token quantity.

paymentMethodId is required. On a SELL, always send savedPaymentMethodId to choose the receiving account. If you omit it, Sinbad selects the customer’s first active matching account.

The response contains one instant offer or up to three alternatives. Each offer includes pricing, display data and a breakdownInput. New fiat searches return a canonical USDT amount in breakdownInput, so the token quantity stays the same through checkout. A closest-amount suggestion can change that quantity.

If no inventory matches, or the amount is outside every listing’s limits, the call returns 200 with empty results. If the only match is a listing that uses the customer’s own wallet, it fails with 400 VALIDATION_ERROR and details.reason: "SELF_TRADE_NOT_ALLOWED".

How offers are chosen

  • Trading hours. Sinbad checks a merchant’s hours only when you send scheduled_at. Setting ignoreTradingHours to true bypasses that check for exact and alternative offers. A merchant’s online status is checked independently.
  • Merchant preference. Exact offers prefer merchants who are not busy and whose effective margin is at most 2%. If no such merchant exists, Sinbad can fall back to busy merchants or higher margins. Alternatives keep the 2% cap and the workload exclusions.
  • Merchant details. Offers, alternatives and breakdowns include the merchant’s fullName, avatarUrl, username, ratingPercent, tradeCount, isSuperMerchant and experienceYears. A breakdown snapshots these values when it is created. Trade history keeps its existing name and avatar display.
  • Display amounts. displayCalculationMode is DUMMY by default, which shows the Card and Sheet values for a fixed 10 USD example. Choose REAL to show the actual requested or suggested amount. Keep the returned breakdownInput unchanged either way, because pricing, breakdowns and transactions always use the actual amount.

Create the breakdown

Call POST /v1/trade-breakdowns with the chosen offer’s breakdownInput, unchanged, and an Idempotency-Key header. Sinbad rechecks the current price, fees, availability and eligibility, then returns the exact terms in tradeDetails and the prepared escrowTransaction. Show tradeDetails to the customer before they sign.

Repeating the call with the same key and body returns the same breakdown and the same deadline. A different body with the same key returns 409 CONFLICT.

A breakdown has a fixed signing window of 300 seconds (5 minutes) from creation. Reading it does not extend the window.

Review before signing

Read the breakdown again with GET /v1/trade-breakdowns/{breakdownId} to check its status. If a SELL needs a token approval, call POST /v1/trade-breakdowns/{breakdownId}/approval and confirm each approval before the customer signs the escrow transaction. See Sell walkthrough.

One open trade per side

Each customer can have one open BUY and one open SELL at a time, scoped to your partner and that customer. Creating a breakdown holds the customer’s place on its side without creating a funded trade. Funding then carries that place into the trade.

Refresh a price by replacing the breakdown

To get a fresh price, create another breakdown on the same side with a new Idempotency-Key. If no escrow transaction has been reported for the earlier breakdown, Sinbad replaces it and returns a new escrowTransaction in the same response. Always sign from the latest response.

After a breakdown is replaced:

  • Reading it, or repeating its original Idempotency-Key, returns 409 CONFLICT.
  • Repeating the key of the current breakdown, with the same body, returns that breakdown with its original deadline.

When creating a breakdown fails

If the earlier breakdown’s escrow transaction was already submitted, funded or put under review (REVIEW_REQUIRED), the new request fails with 409 CONFLICT and details.reason: "ACTIVE_TRADE_EXISTS". Show the customer their existing trade instead of asking again.

When the customer’s place is released

Sinbad releases the customer’s place on a side when:

  • the trade reaches a final status (RELEASED or CANCELED),
  • the customer opens a dispute, or
  • the breakdown expires without being funded.

A dispute that the merchant opens does not release it. If an escrow transaction was reported for the breakdown, Sinbad releases the place only after it confirms on chain that the breakdown expired. That can happen shortly after the 300-second deadline.

Replacing a breakdown does not cancel an escrow transaction that the customer’s wallet has already sent. That transaction can still fund a trade until its original deadline, and it creates its own trade with its original pricing. Keep reporting the hash of every transaction you sent to POST /v1/transactions. Never request a replacement while a wallet send is pending or its outcome is unknown, including before you have reported its hash.

If a replaced breakdown is funded anyway, reading it returns CONFIRMED with its original pricing. It has no new escrowTransaction or approval transactions to sign.