Skip to main content

Markets

Trading-pair metadata: tick size, lot size, minimum notional, fees, listing status.

List Markets

Public — returns every trading pair with its full configuration.

GET /spot/markets

Response — 200 OK

[
{
"id": "DFUSDT",
"base_token": "DF",
"quote_token": "USDT",
"tick_size": "0.0001",
"lot_size": "0.01",
"min_notional": "1",
"maker_fee_bps": 0,
"taker_fee_bps": 0,
"status": "listed"
}
]

Fields

FieldTypeDescription
idstringSymbol the rest of the API uses (e.g. DFUSDT).
base_token / quote_tokenstringToken symbols. Order math: notional = price × quantity (in quote).
tick_sizestringAllowed price increment. Orders with price % tick_size != 0 are rejected with INVALID_TICK.
lot_sizestringAllowed quantity increment. Orders with quantity % lot_size != 0 are rejected with INVALID_LOT.
min_notionalstringMinimum price × quantity for an order. Below → BELOW_MIN_NOTIONAL.
maker_fee_bps / taker_fee_bpsnumberIn basis points (1 bps = 0.01%). MVP testnet defaults: both 0.
statusstringlisted (trading open) / halted (cancels OK, no new orders) / delisted (terminal — all open orders auto-canceled at transition).

Admin: Create Market

Creates a new trading pair. Idempotent on id collision (returns 409 MARKET_EXISTS).

Admin Only

Requires X-API-Key header matching the server's ADMIN_API_KEY env var.

POST /admin/spot/markets

Request Body

{
"id": "DFUSDT",
"base_token": "DF",
"quote_token": "USDT",
"tick_size": "0.0001",
"lot_size": "0.01",
"min_notional": "1",
"maker_fee_bps": 0,
"taker_fee_bps": 0
}
FieldTypeRequiredNotes
idstringYesUnique. Convention: BASE + QUOTE.
tick_size / lot_size / min_notionalstring / numberYesMust be > 0.
maker_fee_bps / taker_fee_bpsnumberYesMust be >= 0.

status is always listed on create. Use the status endpoint below to halt or delist.

Response — 200 OK

{ "ok": true, "id": "DFUSDT" }

After commit, the engine receives a ReloadMarket signal and refreshes its in-memory cache without restart.


Admin: Update Market Config

Patch any subset of tick_size, lot_size, min_notional, maker_fee_bps, taker_fee_bps. Omitted fields stay unchanged.

PATCH /admin/spot/markets/:id

Request Body (all optional)

{
"tick_size": "0.001",
"maker_fee_bps": 5,
"taker_fee_bps": 10
}

Response — 200 OK

{ "ok": true, "id": "DFUSDT" }

Existing open orders are not retroactively re-validated against new tick/lot/min_notional. Only new orders see the updated rules.


Admin: Change Status

Transitions: listed → halted, halted → listed, listed | halted → delisted. delisted is terminal.

PATCH /admin/spot/markets/:id/status

Request Body

{ "status": "halted" }

Status semantics

statusplace new ordercancel existingopen book
listedacceptedacceptedunchanged
haltedrejected MARKET_HALTEDacceptedpreserved
delistedrejected MARKET_DELISTEDn/adrained — all open orders auto-canceled with funds unfrozen, before status flip

Response — 200 OK

{ "ok": true, "id": "DFUSDT", "status": "halted" }

Admin: Credit Balance (testnet only)

Direct off-chain credit to a user's spot wallet. Bypasses the on-chain deposit flow — used for seeding test accounts on testnet.

Testnet Only

Returns 404 DISABLED unless server env has TESTNET_ONLY=true. Mainnet builds answer 404 even with valid auth.

POST /admin/spot/balances/credit

Request Body

{
"user_address": "0xab12...",
"token": "DF",
"amount": "10000",
"reason": "seed mm bot inventory"
}
FieldTypeRequiredNotes
user_addressstringYesLowercased server-side.
tokenstringYesDF or USDT.
amountstring / numberYesDecimal, must be > 0. Added to available; frozen unchanged.
reasonstringNoFree-text audit note.

Both the balance update and an audit row in spot_admin_credits happen in a single DB transaction.

Response — 200 OK

{ "ok": true }

Code Example

import requests

BASE = "https://api-sepolia.p99.world/api/v1"
ADMIN_K = "your_admin_api_key"

# 1. Create the only market
requests.post(f"{BASE}/admin/spot/markets",
headers={"X-API-Key": ADMIN_K, "Content-Type": "application/json"},
json={"id": "DFUSDT", "base_token": "DF", "quote_token": "USDT",
"tick_size": "0.0001", "lot_size": "0.01", "min_notional": "1",
"maker_fee_bps": 0, "taker_fee_bps": 0})

# 2. Seed a test account (testnet only)
for token, amt in [("DF", "10000"), ("USDT", "10000")]:
requests.post(f"{BASE}/admin/spot/balances/credit",
headers={"X-API-Key": ADMIN_K, "Content-Type": "application/json"},
json={"user_address": "0xab12...", "token": token,
"amount": amt, "reason": "manual test"})

# 3. List what's live
print(requests.get(f"{BASE}/spot/markets").json())