Skip to main content
Raw HTTP for intent-based swaps — use from any language when you do not want (or cannot) embed the full SDK orchestrator.
The legacy path /v1/bes/swaps is retired and answers 404. Always use /v1/swaps.

Base URL

Canary: https://canary-api.sodax.com/v1/swaps. All amounts on the wire are decimal strings. Unauthenticated; write endpoints such as submit-tx are rate-limited — the exact limit is not published, so treat 429 as the signal.

Endpoint catalog

Tokens

Quote · deadline

Allowance · approve · create intent

Intent lifecycle

Limit orders · gas · fees


Partner fee

Optional on quote / create-intent / allowance / approve / limit-orders. Not on submit-tx — by then the fee is already encoded in intent.data.
If both amount and percentage are present, amount wins. There is no global default fee.

Bot flow: create, submit-tx, poll

Same for same-chain and cross-chain swaps.

1. Approve (if needed)

POST /approve returns { tx, resetTx? }. Some ERC-20s (notably Ethereum USDT of the 2017 TetherToken lineage) reject allowance changes from one non-zero value to another. When resetTx is present:
  1. Broadcast resetTx and wait for confirmation.
  2. Then broadcast tx.
Native inputs (0x000…000) need no approval.

2. Build + broadcast the intent

Use either:
  • POST /intents (HTTP build) and sign/broadcast tx yourself, or
  • @sodax/sdk sodax.swaps.createIntent({ … }) then continue with HTTP submit-tx.
Wait for the source-chain receipt before step 3.

3. Submit

  • Idempotent on (txHash, srcChainKey) — safe to retry.
  • Response data.status is "inserted" or "duplicate".
  • Rate-limited → back off on 429. Implement your own backoff: @sodax/swaps-api replays a 429 immediately, without one.

4. Poll status

Pipeline:
On success, treat these result fields as the contract for pollers: Optional wire field: the backend may also return result.fillTxHash (solver destination-chain fill) when the solver reported a fill. It can be absent even on solved if the fill was confirmed via the on-chain journal instead. The typed TypeScript contract (SubmitTxStatusResultV2 / @sodax/swaps-api) does not include fillTxHash — that client only types dstIntentTxHash, packetData, and intent_hash. For a typed fill hash, use POST /intents/status (numeric status 3 SOLVED → top-level fillTxHash) or the on-chain journal. On failure, inspect failedAtStep, failureReason, userMessage, intentCancelled, abandonedAt. Open intent after failed fill: if status is failed and the intent is still open on-chain (intentCancelled not true), surface userMessage and cancel to recover funds. Timed intents can also expire via deadline; limit orders (deadline = 0) never expire — cancel explicitly.
Transient relay blips are retried internally and stay on intermediate statuses — they do not appear as failed. Treat failed as real.

5. Optional on-chain journal

Independent of swaps-api self-report (base https://api.sodax.com/v1/be):
  • Sonic-source create tx: GET /intent/tx/:txHash
  • Cross-chain: GET /intent/:intentHash
Lifecycle: 404 → open → filled/cancelled. Aggregator lag means this can trail submit-tx/status — soft check only.

Three different status fields

Do not mix these up:

Long-poll: solved packet

POST /intents/packet is a server-side long-poll — one request held until the fill packet lands or timeout elapses (default ~60s). Call once and await; do not spin client-side.

Quote sketch

Exact field names follow the OpenAPI / @sodax/types QuoteRequestV2 shapes — prefer generating clients from the live schema if you are not on TypeScript.

TypeScript clients (optional)

Two packages hit the same HTTP API with different error contracts:

SDK adapter (Result<T>)

Standalone client (throws)


Operational checklist

  • Source balance ≥ inputAmount + gas; use a fresh, tip-synced RPC
  • Approve once (or large allowance) when possible
  • Wait for source-chain receipt before submit-tx
  • Respect rate limits; retry submit freely (idempotent)
  • Poll until solved / failed; log failure fields
  • Cross-chain destination funds may lag solved by minutes — poll destination balance with a generous timeout if the next step depends on arrival

See also