Skip to main content
The SaucerSwap V3 Orderbook API is designed for programmatic trading clients, market makers, wallets, dashboards, analytics surfaces, and other integrations that need order placement, cancellation, account order state, and live orderbook data. The documentation is public. Protected API calls require wallet authentication, and production users should expect rate and service-protection limits. Teams planning sustained high-volume traffic should contact [email protected] so we can coordinate limits and support.
This API is separate from the legacy SaucerSwap REST API. The legacy REST API uses x-api-key authentication. The V3 Orderbook API uses wallet challenge authentication and short-lived JWTs.

Integration Flow

PhaseWhat your client doesPrimary API surface
AuthenticateSign a challenge with the trading accountPOST /auth/challenge, POST /auth/verify
Discover marketsList orderbooks, fees, and onboarding statusGET /books, GET /fees/:orderbookId, GET /onboarding/:orderbookId/status
Read market dataFetch a depth snapshot and subscribe to diffsGET /depth/:orderbookId, /ws/depth
Place ordersBuild, sign, and save ordersGET /signature/domain, POST /orders/build, POST /orders/save
ReconcileTrack order events and recover state after reconnects/ws/user-events, GET /orders, GET /orders/:orderId/history
CancelRequest cancellation or submit on-chain cancellationPOST /cancel, POST /cancel/all, reactor cancellation
Authenticate first, then use testnet before moving the same flow to mainnet. Move to mainnet after your client handles authentication renewal, WebSocket reconnects, cancellation finality, and integer string handling correctly.

Environments

EnvironmentAPI base URLHedera Mirror Node
Testnethttps://testnet-orderbook-api.saucerswap.financehttps://testnet.mirrornode.hedera.com
Mainnethttps://orderbook-api.saucerswap.financehttps://mainnet.mirrornode.hedera.com
WebSocket streams use the same host with the wss:// scheme.

Authentication

All protected endpoints require a JWT issued by the /auth flow. Attach the JWT to REST calls with:
Authorization: Bearer <token>
The challenge and verify endpoints are the only unauthenticated calls:
StepEndpointPurpose
1POST /auth/challengeSubmit accountId and receive a nonce message to sign
2client-side signingSign the challenge with the account key
3POST /auth/verifySubmit accountId and signature; receive a JWT
Challenge request:
{ "accountId": "0.0.123456" }
Challenge response:
{ "message": "..." }
Verify request:
{
  "accountId": "0.0.123456",
  "signature": "0x..."
}
Verify response:
{ "token": "jwt" }
Supported account identifiers:
Account formatSupported key typesNotes
0.0.XED25519, ECDSA_SECP256K1Key type is resolved through the Hedera Mirror Node
0x...ECDSA_SECP256K1Treated as an EVM account
JWTs are short-lived. Re-authenticate before a long-running session expires or whenever a protected call returns 401.
Never put a primary wallet private key in a bot process. Use a dedicated integration account, store secrets server-side, and start on testnet before placing mainnet orders.

Endpoint Summary

CategoryEndpointDescription
MarketsGET /booksList available orderbooks
Market dataGET /depth/:orderbookIdFetch a full depth snapshot
FeesGET /fees/:orderbookId?side=makerFetch fee rates for an orderbook side
OnboardingGET /onboarding/:orderbookId/statusCheck whether the account can trade a market
OrdersGET /ordersList authenticated account orders
OrdersGET /orders/:orderId/historyFetch per-order event history
SigningGET /signature/domainFetch the EIP-712 domain for the active environment
PlacementPOST /orders/buildBuild unsigned orders with server-assigned nonces
PlacementPOST /orders/saveSubmit signed orders
CancellationPOST /cancelRequest cancellation for specific order IDs
CancellationPOST /cancel/allEmergency cancel by nonce floor
WebSocket/ws/depthSubscribe to live orderbook depth diffs
WebSocket/ws/user-eventsSubscribe to authenticated order events

Market Discovery

Use GET /books to discover tradable orderbooks before building orders. Key market fields include token identifiers, market status, trading increments, and the current AMM-routing flag:
interface OrderbookItem {
  id: number
  baseTokenId: string
  quoteTokenId: string
  baseTokenEvmAddress: string
  quoteTokenEvmAddress: string
  status: string // 'OPEN' | 'CLOSED'
  isAMMEnabled: boolean // whether AMM liquidity is routed into this book
  isMarketHalted: boolean
  baseTokenSymbol: string | null
  quoteTokenSymbol: string | null
  baseTokenDecimals: number | null // token decimals, e.g. 8 for WBTC
  quoteTokenDecimals: number | null // token decimals, e.g. 6 for USDC
  tickStep: string
  sizeStep: string
  lotSize: string
  minNotional: string
}
Additional price, volume, and timestamp fields may also be present. Use the returned EVM token addresses for inputToken and outputToken when building orders. Use baseTokenDecimals and quoteTokenDecimals when converting between human-readable display amounts and raw token amounts. Keep the build, sign, and save path on raw token units. If isAMMEnabled is true, AMM liquidity can be routed into that book when an order request also opts into AMM-backed settlement.

Place Orders

Order placement is a build, sign, save flow:
  1. Fetch the signing domain with GET /signature/domain.
  2. Build orders with POST /orders/build.
  3. Sign the returned order structs client-side.
  4. Save signed orders with POST /orders/save.

1. Fetch the Domain

The signing domain is environment-specific. Fetch it once and cache it for the session.
const domain = await client.getDomain()
// { name, version, chainId, verifyingContract }
verifyingContract is the reactor contract address used for signatures, and chainId identifies the Hedera network.

2. Build Orders

const orders = await client.buildOrders([
  {
    orderbookId: '3',
    type: 'LIMIT',
    deadline: String(Math.floor(Date.now() / 1000) + 3600),
    inputToken: '0xbase-token-evm-address',
    inputAmount: '1000000',
    outputToken: '0xquote-token-evm-address',
    outputAmount: '950000',
    makerOnly: false,
    takerOnce: false,
    isAMMEnabled: true,
  },
])
The server assigns each order nonce and returns the serialized order struct to sign. Always sign the returned order object, not your original request object.
FieldTypeRequiredDescription
orderbookIdstringYesMarket ID
typeLIMIT or MARKETYesOrder type
deadlinestringLIMIT onlyUnix timestamp in seconds. Omit for market orders.
inputTokenstringYesEVM address of the token being sold
inputAmountstringYesRaw token amount, in smallest units
outputTokenstringYesEVM address of the token being bought
outputAmountstringYesMinimum raw output amount. Use "1" for market orders.
recipientstringNoOutput recipient EVM address
makerOnlybooleanNoRestrict order to maker fills
takerOncebooleanNoAllow only one taker fill
isAMMEnabledbooleanNoPermit AMM-backed settlement
Keep all integer quantities as strings. Do not cast nonces, deadlines, or raw token amounts to JavaScript numbers before signing.

3. Sign Orders

Sign only the EIP-712 order fields. Exclude metadata returned by the API. The signature wire format starts with a one-byte mode prefix:
PrefixModeTypical use
0x00EIP-712ECDSA bot clients and ED25519 bot clients signing the EIP-712 hash
0x01Hedera personal signWallet flows that return a HIP-632 SignatureMap for a HIP-820 Hedera personal-sign payload
Do not strip the prefix. The reactor and backend use the prefix to choose the verifier.
const signature = await client.signOrder(orders[0], privateKey, domain)

4. Save Orders

const { orders: saved } = await client.saveOrders([
  {
    order: orders[0],
    signature,
    orderbookId: '3',
    type: 'LIMIT',
  },
])
The response returns an orders array with saved order objects and meta.status populated. If ocoLinks were supplied, the response may also include an oco block with link status.

OCO Orders

POST /orders/save also supports optional one-cancels-the-other metadata through ocoLinks. OCO links are server-side transport metadata; they are not included in the EIP-712 digest and are not submitted to the reactor. Each link pairs two items in the same save request:
{
  "items": [
    { "order": {}, "signature": "0x...", "orderbookId": "3", "type": "LIMIT" },
    { "order": {}, "signature": "0x...", "orderbookId": "3", "type": "LIMIT" }
  ],
  "ocoLinks": [
    { "a": 0, "b": 1 }
  ]
}
OCO pairs must share the same orderbookId and swapper, and currently only LIMIT orders are supported in OCO pairs.

Policy Limits

The API applies these limits automatically:
ConstraintValue
Max open orders per wallet5,000
Min order deadline30 seconds from now
Max order deadline90 days from now
Max orders per build/save request250
Max orders per cancel request500
If a requested deadline exceeds the max, the server may clamp the returned order deadline. Always sign the deadline in the built order response.

Cancellations

Cancellation endpoints are asynchronous. A 202 Accepted response means the cancellation request was accepted; it does not mean the order is already cancelled. Use the user-event WebSocket or GET /orders/:orderId/history to confirm the final ORDER_CANCELED event. POST /cancel accepts up to 500 order IDs per request. Split larger cancellation batches into multiple requests and reconcile each accepted order through the user-event stream or order history.
EndpointDescription
POST /cancelRequest cancellation for one or more order IDs
POST /cancel/allEmergency cancel by nonce floor
The on-chain reactor remains the source of truth. Advanced clients can also submit on-chain cancellations directly to the reactor, then rely on indexer reconciliation.

WebSockets

Both streams require a valid JWT in the token query parameter:
wss://<host>/ws/depth?token=<jwt>&books=<id>,<id>
wss://<host>/ws/user-events?token=<jwt>&books=<id>,<id>
Treat WebSocket URLs as sensitive because they contain the JWT. Avoid logging full URLs in production. For reliable depth handling:
  1. Connect to the depth stream.
  2. Buffer diffs while fetching the REST depth snapshot.
  3. Apply buffered diffs after the snapshot.
  4. Continue applying live diffs.
Re-authenticate before each reconnect attempt. Active WebSocket connections are verified at handshake time; a connection can remain open after its original JWT expires.

Production Checklist

Before placing sustained mainnet flow, confirm your client can:
  • re-authenticate after 401 responses
  • reconnect WebSockets with backoff
  • rebuild local books from snapshot plus buffered diffs
  • treat cancellation 202 responses as acknowledgements, not final states
  • keep all uint256 values as strings through signing and saving
  • use the orderbook token decimals when converting raw amounts for display or order sizing
  • store JWTs and private keys only in server-side secret storage
  • monitor open order count, deadlines, and rate-limit responses
  • reconcile user events with GET /orders/:orderId/history after reconnects

Error Format

Errors are returned as:
{ "error": "message string" }
Common statuses:
StatusMeaning
400Invalid request
401Missing or expired JWT
403Authenticated account is not allowed to perform the action
404Resource not found
429Rate limited
500Server error

TypeScript Client

For a server-side bot example, see TypeScript Bot Client.