API Trading
Get your quoting system connected and operational.
Base URL: https://testnet-api.hypercall.xyz/ | Full reference: API Reference
Prerequisites
- Wallet: An EVM wallet capable of signing EIP-712 typed messages
- API Access: Base URL for the environment
- Markets: At least one market must exist (check via
GET /markets)
Step 1: Discover Markets
Query available instruments:
# List all markets (underlying + expiry groups)
curl https://testnet-api.hypercall.xyz/markets
# List instruments for a currency
curl "https://testnet-api.hypercall.xyz/instruments?currency=BTC"
# Get options summary with best bid/ask
curl "https://testnet-api.hypercall.xyz/options-summary?currency=BTC"
Response format: JSON-RPC envelope (Deribit-compatible) for instruments/options-summary.
See REST API for full endpoint details.
Step 2: Configure Authentication
Option A: Direct Wallet Signing
Sign orders directly with your trading wallet. Each order requires:
wallet: Your wallet addressnonce: Unique incrementing noncesignature: EIP-712 signature of the order payload
See Authentication & Signing for exact signing requirements.
Option B: Agent Authorization (Recommended for MMs)
Use a dedicated signing key (agent) to place orders on behalf of your trading wallet:
# Approve an agent wallet to sign for your trading wallet
curl -X POST https://testnet-api.hypercall.xyz/approve-agent \
-H "Content-Type: application/json" \
-d '{
"agent": "0x...",
"nonce": 1,
"signature": "0x..."
}'
The agent wallet signs the approval message. Once approved, the agent can place/cancel orders for the trading wallet.
See Agent Authorization for full details.
Step 3: Start Quoting (Bulk Orders)
Preferred method for market makers: Use POST /bulk_order to place up to 50 orders per request.
curl -X POST https://testnet-api.hypercall.xyz/bulk_order \
-H "Content-Type: application/json" \
-d '{
"orders": [
{
"wallet": "0x...",
"symbol": "BTC-20250131-100000-C",
"price": "100.0",
"size": "0.1",
"side": "Buy",
"tif": "gtc",
"client_id": "mm-bid-1",
"mmp_enabled": true,
"nonce": 1,
"signature": "0x..."
},
{
"wallet": "0x...",
"symbol": "BTC-20250131-100000-C",
"price": "101.0",
"size": "0.1",
"side": "Sell",
"tif": "gtc",
"client_id": "mm-ask-1",
"mmp_enabled": true,
"nonce": 2,
"signature": "0x..."
}
]
}'
Critical constraints:
priceandsizeMUST be strings (required for signature verification)- Price must have ≤ 5 significant figures (e.g.,
"12345"valid,"123456"rejected) - Size is human-readable; engine converts via multiplier
1_000_000(truncates to integer) - Max 50 orders per bulk request
Response: Each order returns an OrderUpdateMessage with status (ACKED, OPEN, FILLED, REJECTED, etc.).
See REST API for full bulk order specification.
Step 4: Subscribe to WebSocket Feeds
Connect to real-time updates:
// Public connection (no auth)
const ws = new WebSocket('wss://testnet-api.hypercall.xyz/ws');
// Private connection (for order_updates, fills, portfolio)
const ws = new WebSocket('wss://testnet-api.hypercall.xyz/ws?wallet=0x...');
Subscribe to channels:
// Subscribe to orderbook updates
ws.send(JSON.stringify({ type: "Subscribe", channel: "orderbook" }));
// Subscribe to your order updates (requires ?wallet=)
ws.send(JSON.stringify({ type: "Subscribe", channel: "order_updates" }));
// Subscribe to fills (requires ?wallet=)
ws.send(JSON.stringify({ type: "Subscribe", channel: "fills" }));
// Subscribe to trades (public)
ws.send(JSON.stringify({ type: "Subscribe", channel: "trades" }));
// Subscribe to market updates (public)
ws.send(JSON.stringify({ type: "Subscribe", channel: "market_updates" }));
Important behavior:
order_updatesintentionally omitsPARTIALLY_FILLEDstatus updates- Use the
fillschannel as the source of truth for partial fill tracking - No snapshot-on-subscribe; use REST
GET /orderbookfor initial state - The server sends websocket
Pingframes every 20 seconds and requiresPongwithin 60 seconds - Browser clients answer automatically. Many websocket libraries, including
tungsteniteandtokio-tungstenite, also handle control-frame ping/pong automatically. Raw socket clients must implementPing/Pong.
See WebSocket API for complete WebSocket protocol.
Step 5: Configure MMP (Market Maker Protection)
MMP protects against rapid adverse fills by canceling orders when limits are breached.
# Configure MMP for a wallet+currency
curl -X POST https://testnet-api.hypercall.xyz/mmp-config \
-H "Content-Type: application/json" \
-d '{
"wallet": "0x...",
"currency": "BTC",
"interval_ms": 60000,
"frozen_time_ms": 300000,
"qty_limit": 1000000,
"delta_limit": 10.0,
"vega_limit": 5.0,
"enabled": true,
"nonce": 1,
"signature": "0x..."
}'
MMP behavior (critical to understand):
- Fills are accepted first, then MMP checks cumulative metrics
- If limits breached: remaining quantity on active order stops, order becomes
CANCELEDwith reason"MMP triggered during fill processing" - All other MMP-enabled orders for the same wallet+underlying are auto-canceled
- Cancel reason:
"Order canceled by MMP trigger"
See MMP for full MMP semantics.
Step 6: Monitor and Reconcile
Order Lifecycle
Orders transition through states:
ACKED: Accepted, queued for matchingOPEN: Resting on orderbookPARTIALLY_FILLED: Partially executed (not sent on WSorder_updates)FILLED: Fully executedCANCELED: Canceled by user or MMPREJECTED: Rejected by engine (margin, tier, expired, etc.)
Reconciliation Rules
Truth sources:
- Order status:
GET /orders?wallet=...or WSorder_updates(excludesPARTIALLY_FILLED) - Fills:
GET /fills?wallet=...or WSfillschannel (source of truth for partial fills) - Portfolio:
GET /portfolio?wallet=...or WSportfoliochannel
Rejection handling:
- Most rejections return HTTP 200 with
OrderUpdateMessage.status = "REJECTED" - Check
reasonfield for exact rejection cause - Common reasons:
"Insufficient margin: worst case margin=...","Tier1 users cannot go short...","Instrument has expired"
See Errors for handling rejections and error codes.
Step 7: Understand Margin Requirements
Before quoting, understand the margin model:
- Portfolio margin: SPAN-based calculation across all positions and open orders
- Stress scenarios: Worst-case loss computed across multiple scenarios (spot change, vol change, skew change, kurtosis change)
- Pre-trade check: Orders rejected if
worst_loss + cash < 0in any scenario
See Margining for complete margin semantics.
Next Steps
- Full API reference: REST API
- WebSocket protocol: WebSocket API
- Margining: Margining Overview
- Operations: Runbooks for integration certification
Common Issues
"Signature verification failed"
- Ensure
priceandsizeare strings (not numbers) - Verify string formatting matches exactly what was signed
- Check nonce is correct and incrementing
"Insufficient margin"
- Check portfolio via
GET /portfolio?wallet=... - Review margin calculation in Margining
- Ensure account has sufficient cash balance
"Tier1 users cannot go short"
- Your wallet is set to
tier1(long-only) - Upgrade to
tier2viaPOST /user-tier(requires admin or signature) - Or ensure all sells are covered by filled long positions
No fills on WebSocket
- Verify you connected with
?wallet=...for private channels - Check you subscribed to
fillschannel - Use
GET /fills?wallet=...as fallback