- Implements the
ISwapsApiV2contract from@sodax/typesoverfetch. - Validates every response at runtime with valibot, and
transforms each chain-specific unsigned
txback to its domain shape (decimal-string →bigint, Injective index-object bytes →Uint8Array). - Zero dependency on
@sodax/sdk, viem, or wallet providers — only@sodax/types(types) andvalibot.
@sodax/sdk’s SwapsApiService
(sodax.api.swaps) is a thin adapter over this package, adding the SDK’s
Result<T> contract, logger, and transport-config resolution on top. Use
@sodax/swaps-api directly when you want just the swaps backend without pulling in
the full SDK.
Install
valibot is a regular dependency of this package, not a peer — installing it separately is unnecessary.
Usage
baseUrl is required and injected by the caller — the package never hardcodes
environment URLs. Optionally set timeout (ms — an overall per-call deadline that
includes retries; on expiry the call throws TIMEOUT_ERROR), a custom fetch (for
tests or non-standard runtimes; it receives the timeout AbortSignal), extra headers,
and an apiKey.
Methods
One method per Swaps API endpoint, mirroringISwapsApiV2:
quoteType is 'exact_input' — exact-output quoting is not supported.
API key
The backend guardsPOST /swaps/* routes with an x-api-key header check (keys are
minted through the partner portal). Pass the key once at construction and the client
sends it on every request:
headers: { 'x-api-key': ... } wins over the apiKey convenience option.
For a different key per call, construct another client — instances are cheap and
stateless. Keys bundled into a browser app are public by nature: from a browser, point
baseUrl at your own backend proxy and attach the key there — see API key good practices.
Auth failures surface as HTTP_ERROR with the backend’s status and message on
context: 401 (missing or invalid key) and 403 (suspended organisation or missing
scope) are terminal — fix the key, don’t retry. The one transient case, a 503 whose
message is API key verification is temporarily unavailable (exported as
API_KEY_VERIFICATION_UNAVAILABLE_MESSAGE), is retried automatically with a short
backoff — for every call, mutations included, since the guard rejects before the route
handler runs.
Partner fees
partnerFee has no default — this client forwards the body as given and does not read
new Sodax({ fee }) / new Sodax({ swaps: { partnerFee } }). Send the same value on
quote and create-intent:
checkAllowance / approve inherit the field but ignore it. See
MONETIZE_SDK.md
for the orchestrator path.
Errors
Every method throws aSwapsApiError on failure — a single typed error whose
code is one of NETWORK_ERROR / TIMEOUT_ERROR / HTTP_ERROR / PARSE_ERROR /
VALIDATION_ERROR, with diagnostic context (endpoint, method, path, HTTP status,
validation issues) and the underlying failure on .cause. Idempotent calls (reads,
polls, pure-compute POSTs like getQuote) retry transient HTTP / network failures up to
3 attempts in total — the first try plus two retries, back to back with no delay; a
timeout and mutating calls are never retried — except the apiguard’s verification
503 (see “API key” above), which is replay-safe, retried for every call, and the one
retry that backs off. The budget is per call, so a caller that retries too (a React
Query hook, say) multiplies against it.
Note: this throwing contract is intentional and distinct from@sodax/sdk’ssodax.api.swaps, which wraps these calls and returnsResult<T>instead of throwing.
Response schemas
The valibot schemas the client validates with are exported too, so a caller that already holds a parsed response — or a sibling API whose wire shapes are identical — can reuse them instead of re-declaring the contract.@sodax/sdk’s Leverage Yield client is exactly that case: a
leverage-yield deposit/withdraw is an intent-based swap, so it reuses these for its intent-relay,
gas, fee, and submit-tx responses.
- Intent lifecycle:
makeCreateIntentResponseSchema,makeCancelIntentResponseSchema,SubmitIntentResponseSchema,StatusResponseSchema,IntentHashResponseSchema,IntentPacketResponseSchema,IntentResponseSchema,RelayExtraDataResponseSchema,IntentStateSchema - Quote · deadline · allowance · approve:
makeQuoteResponseSchema,DeadlineResponseSchema,AllowanceCheckResponseSchema,makeApproveResponseSchema - Gas · fees:
GasEstimateResponseSchema,FeeResponseSchema - Submit-tx state machine:
SubmitTxResponseSchema,SubmitTxStatusResponseSchema - Raw transactions:
rawTxSchemaForChainKey(chainKey)— the per-chain-familytxschema themake*ResponseSchemafactories above take, which also transforms the unsigned tx back to its domain shape (decimal-string →bigint, Injective index-object bytes →Uint8Array)
Reference app
apps/swap-api-example
drives this client end to end against a live Swaps API host.