Wallet-authenticated API · v1

Ignite Authenticated Trading API

Connect an EVM wallet, create a short-lived Ignite session, read the wallet's account state, and place or cancel orders. Standard wallets use EIP-712; Thanos Wallet uses its published SIWE personal_sign flow. Authentication proves wallet control; Ignite never requests a private key or seed phrase.

Authentication flow

1. Request a challenge

Send the wallet address. The challenge is valid for five minutes and replaces any earlier challenge for that address.

2. Sign typed data

Sign the returned typedData object as EIP-712 data. Do not sign the human-readable challenge hint.

3. Verify the signature

Send the address and signature. A valid, unused challenge returns an eight-hour bearer session.

4. Call protected routes

Send Authorization: Bearer <token>. Responses are always scoped to the authenticated wallet.

Request a wallet challenge

POST /v1/auth/challenge

The EIP-712 domain intentionally has no chain ID, so the login is not tied to the wallet's currently selected network.

curl -X POST https://api.ignite.trade/v1/auth/challenge \
  -H "Content-Type: application/json" \
  -d '{"address":"0xYOUR_WALLET"}'

{
  "typedData": {
    "domain": { "name": "Ignite DEX", "version": "1" },
    "types": { "Login": [
      { "name": "address", "type": "address" },
      { "name": "nonce", "type": "string" },
      { "name": "issuedAt", "type": "string" }
    ]},
    "primaryType": "Login",
    "message": {
      "address": "0xYOUR_WALLET",
      "nonce": "single-use-random-value",
      "issuedAt": "2026-07-27T12:00:00.000Z"
    }
  },
  "expiresIn": "5m"
}

Verify and create a session

POST /v1/auth/verify
// viem example
const challenge = await fetch('https://api.ignite.trade/v1/auth/challenge', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ address: account.address })
}).then((response) => response.json());

const signature = await walletClient.signTypedData({
  account,
  ...challenge.typedData
});

const session = await fetch('https://api.ignite.trade/v1/auth/verify', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ address: account.address, signature })
}).then((response) => response.json());

// { "verified": true, "token": "<session JWT>" }
A nonce is single-use. A replay, expired nonce, changed address, or altered typed message is rejected.
Treat the returned token as a temporary credential. Keep it out of URLs and logs and discard it after eight hours.

Thanos Wallet SIWE compatibility

GET + POST /api/auth/nonce · /api/auth/verify

Thanos Wallet signs an EIP-4361 SIWE message with personal_sign. Request a nonce for the wallet, build the SIWE message with the current Ignite domain and URI, sign that exact message, then verify it. The returned sessionToken is the same eight-hour bearer credential used by all protected routes.

const nonce = await fetch(
  'https://api.ignite.trade/api/auth/nonce?address=' + account.address
).then((response) => response.text());

// Use thanos-connect's buildSiweMessage() so the signed bytes match.
const message = buildSiweMessage({
  domain: window.location.host,
  address: account.address,
  uri: window.location.origin,
  statement: 'Sign in to Ignite DEX with your Thanos Wallet.',
  chainId,
  nonce,
  expirationTime: new Date(Date.now() + 5 * 60_000).toISOString()
});

const signature = await walletClient.signMessage({ account, message });
const { sessionToken } = await fetch('https://api.ignite.trade/api/auth/verify', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ address: account.address, message, signature })
}).then((response) => response.json());
This compatibility path is for Thanos Wallet only. Do not send an EIP-712 signature to the SIWE verifier, and never reuse a nonce or signed message.

Authoritative market rules

Read GET /v1/markets before submitting an order. Each market record is authoritative for symbol, type, status, tradingEnabled, feeBps, tickSize, minOrderSize, maxOrderSize, token symbols, and network ID.

The current API does not advertise a separate quantity-step field. Clients must enforce the published minimum and maximum size, then handle server validation responses. Never infer limits from UI formatting.

Balances and positions

GET /v1/portfolio/{address}

Returns equity, free collateral, balances and positions for the authenticated wallet only. The path address must match the bearer-token subject; another wallet is rejected.

curl https://api.ignite.trade/v1/portfolio/0xYOUR_WALLET \
  -H "Authorization: Bearer $IGNITE_TOKEN"

Place an order

POST /v1/orders
curl -X POST https://api.ignite.trade/v1/orders \
  -H "Authorization: Bearer $IGNITE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "market": "LITHO/USDT",
    "side": "buy",
    "type": "limit",
    "price": 8.70,
    "size": 1,
    "clientOrderId": "strategy-a-000001",
    "timeInForce": "GTC",
    "postOnly": false,
    "reduceOnly": false
  }'
FieldAccepted valuesRule
marketPublished market symbolRequired; must be active and trading-enabled.
sidebuy | sellRequired. Market-specific restrictions still apply.
typelimit | marketRequired. Limit orders should include price.
pricePositive numberMust align to tickSize when the market publishes one.
sizePositive numberRequired except quote-denominated market buys; min/max rules apply.
quoteAmountPositive numberOnly for market buys; cannot be combined with size.
clientOrderId1–128 charactersRecommended account-scoped idempotency key. A retry returns the original result.
timeInForceGTC | IOC | FOKDefaults to GTC. Market orders terminate any unfilled remainder.
postOnlybooleanRejects an order that would immediately take liquidity.
reduceOnlybooleanRelevant only to supported position markets; cannot increase or flip a position.
accountWallet addressOptional; if supplied it must equal the authenticated wallet.

List wallet orders

GET /v1/orders

Returns only orders belonging to the authenticated wallet, including open and terminal states.

curl https://api.ignite.trade/v1/orders \
  -H "Authorization: Bearer $IGNITE_TOKEN"

Cancel an order

DELETE /v1/orders/{orderId}

Only the authenticated owner can cancel a live order. Filled, rejected, expired, failed, or already-cancelled orders cannot be cancelled.

curl -X DELETE https://api.ignite.trade/v1/orders/ORDER_ID \
  -H "Authorization: Bearer $IGNITE_TOKEN"

Wallet fills

GET /v1/trades?market={symbol}&limit=100

Returns fills where the authenticated wallet was maker or taker. The optional limit is clamped to 1–500 and the optional market filter uses the published market symbol.

Responses and integration safety

400 Bad Request

Malformed input, invalid signature, market rule failure, insufficient balance, or an order that cannot be accepted.

401 Unauthorized

Missing, invalid, or expired bearer token. Request a new challenge and session; do not retry with the same expired token.

403 Forbidden

The requested account or object does not belong to the authenticated wallet.

404 Not Found

Unknown market or resource. Refresh the market list before retrying.

409 Conflict

Account state requires a current action, such as accepting a new terms version.

429 Too Many Requests

Honor RateLimit headers and retry only after the published reset time with exponential backoff.

Admin, custody-operator, RPC credentials, internal service routes, and automation-signer details are intentionally outside this public integration contract.