API Reference
REST API endpoint specifications
The API server provides REST endpoints for reading protocol data. All write operations go directly to smart contracts.
Note: In the current implementation, the quote currency is always USDC. All trading pairs are denominated against USDC (e.g., BTC-USDC, ETH-USDC) because USDC is used as the collateral currency. Settlement is always in USDC.
Health Check
GET /health
Check if the API server is running.
Response:
Prop
Type
Example:
curl "http://localhost:8080/health"{
"status": "ok",
"timestamp": 1736409000000
}Base URL
| Environment | URL |
|---|---|
| Local | http://localhost:8080 |
| Production | https://api.diffusal.xyz |
OpenAPI Documentation
The API provides an interactive OpenAPI (Swagger) interface for exploring endpoints:
| Environment | OpenAPI URL |
|---|---|
| Local | http://localhost:8080/openapi |
| Production | https://api.diffusal.xyz/openapi |
Additional formats:
- JSON spec:
/openapi/json - YAML spec:
/openapi/yaml - LLM-friendly:
/llms.txt(markdown format optimized for AI consumption)
Authentication Endpoints
Authentication uses SIWE (Sign-In with Ethereum) via Better Auth. See Authentication for the full flow.
Better Auth endpoints are mounted at /api/auth/*. Custom wallet endpoints are at /auth/api/*.
Authentication Flow
CLIENT WALLET SERVER
│ │ │
├── GET /api/auth/siwe/nonce?walletAddress=0x... ───►│
│ │ │
│◄── { nonce: "random32chars" } ────────────────────┤
│ │ │
│ Construct SIWE message │ │
│ (EIP-4361) │ │
│ │ │
├── Request signature ──────►│ │
│ │ │
│◄── Signature (0x...) ─────┤ │
│ │ │
├── POST /api/auth/siwe/verify ─────────────────────►│
│ { message, signature } │
│ │ Verify signature │
│ │ Create session │
│◄── { session, user } + Set-Cookie ────────────────┤
│ │ │
│ ─────────────────────────────────────────────────┐│
│ Subsequent requests include session cookie ││
│ ─────────────────────────────────────────────────┘│
│ │ │
├── GET /account/me (with cookie) ──────────────────►│
│ │ Validate session │
│◄── User profile data ─────────────────────────────┤GET /api/auth/siwe/nonce
Request a nonce for SIWE message signing.
| Parameter | Type | Description |
|---|---|---|
walletAddress | query | User's Ethereum address |
Response:
| Field | Type | Description |
|---|---|---|
nonce | string | Random 32-character nonce |
Example:
curl "http://localhost:8080/api/auth/siwe/nonce?walletAddress=0x742d35Cc..."{
"nonce": "abc123xyz789def456ghi012jkl345mno"
}POST /api/auth/siwe/verify
Verify a signed SIWE message and create a session.
Request Body:
| Field | Type | Description |
|---|---|---|
message | string | SIWE message (EIP-4361 format) |
signature | string | Wallet signature |
Response:
| Field | Type | Description |
|---|---|---|
session | object | Session details |
user | object | User profile |
Note: Session cookie is set automatically.
Example:
curl -X POST "http://localhost:8080/api/auth/siwe/verify" \
-H "Content-Type: application/json" \
-d '{
"message": "localhost:3000 wants you to sign in with your Ethereum account:\n0x742d35Cc...\n\nSign in to Diffusal\n\nURI: http://localhost:3000\nVersion: 1\nChain ID: 10143\nNonce: abc123xyz789def456ghi012jkl345mno\nIssued At: 2024-01-09T12:00:00.000Z",
"signature": "0x..."
}'{
"session": {
"id": "session_abc123",
"expiresAt": "2024-01-16T12:00:00.000Z"
},
"user": {
"id": "user_xyz789",
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f1F321"
}
}POST /api/auth/sign-out
Sign out and invalidate the current session.
Example:
curl -X POST "http://localhost:8080/api/auth/sign-out" \
-H "Cookie: session=..."{
"success": true
}GET /api/auth/session
Get current session information.
Response:
| Field | Type | Description |
|---|---|---|
user | object | User profile (or null) |
session | object | Session details (or null) |
Example:
curl "http://localhost:8080/api/auth/session" \
-H "Cookie: session=..."{
"user": {
"id": "user_xyz789",
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f1F321"
},
"session": {
"id": "session_abc123",
"expiresAt": "2024-01-16T12:00:00.000Z"
}
}GET /auth/api/wallets
List all wallets linked to the current user (requires auth).
Response:
Prop
Type
Wallet Object:
Prop
Type
Example:
curl "http://localhost:8080/auth/api/wallets" \
-H "Cookie: session=..."{
"wallets": [
{
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f1F321",
"isPrimary": true,
"linkedAt": "2024-01-09T12:00:00.000Z"
}
],
"total": 1
}GET /auth/api/wallets/primary
Get the primary wallet address for the current user (requires auth).
Response:
Prop
Type
Example:
curl "http://localhost:8080/auth/api/wallets/primary" \
-H "Cookie: session=..."{
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f1F321",
"userId": "user_abc123"
}POST /auth/api/wallets/verify
Verify wallet ownership using SIWE signature.
Request Body:
Prop
Type
Response:
Prop
Type
Example:
curl -X POST "http://localhost:8080/auth/api/wallets/verify" \
-H "Content-Type: application/json" \
-H "Cookie: session=..." \
-d '{
"message": "localhost:3000 wants you to sign in...",
"signature": "0x...",
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f1F321"
}'{
"success": true,
"message": "Wallet verified",
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f1F321"
}Public Market Data
No authentication required for these endpoints.
GET /markets
List all active options markets (series).
Query Parameters:
Prop
Type
Pagination: Use
cursorfromnextCursorin the response to fetch the next page. Returns up tolimitresults (default 20, max 100).
Response:
Prop
Type
Market Object:
Prop
Type
Example:
curl "http://localhost:8080/markets?limit=10&pairId=0x..."{
"markets": [
{
"seriesId": "0x1a2b3c4d...",
"symbol": "BTC-82000-C-1736409600",
"pairId": "0xabcd1234...",
"pairSymbol": "BTC-USDC",
"strike": "82000000000000000000000",
"expiry": 1736409600,
"isCall": true,
"isSettled": false
}
],
"total": 1,
"hasMore": false,
"nextCursor": null
}GET /markets/pairs
List all registered trading pairs.
Response:
Prop
Type
Pair Object:
Prop
Type
Example:
curl "http://localhost:8080/markets/pairs"{
"pairs": [
{
"pairId": "0xabcd1234...",
"symbol": "BTC-USDC",
"baseCurrency": "BTC",
"quoteCurrency": "USDC"
},
{
"pairId": "0xef567890...",
"symbol": "ETH-USDC",
"baseCurrency": "ETH",
"quoteCurrency": "USDC"
}
]
}GET /markets/orderbook/:symbol
Get aggregated order book for a series.
Path Parameters:
Prop
Type
Query Parameters:
Prop
Type
Response:
Prop
Type
Level Object:
Prop
Type
Example:
curl "http://localhost:8080/markets/orderbook/BTC-82000-C-1736409600?depth=5"{
"symbol": "BTC-82000-C-1736409600",
"seriesId": "0x1a2b3c4d...",
"bids": [
{
"price": "1500000000000000000",
"size": "5000000000000000000",
"orderCount": 3
},
{
"price": "1400000000000000000",
"size": "10000000000000000000",
"orderCount": 5
}
],
"asks": [
{
"price": "1600000000000000000",
"size": "3000000000000000000",
"orderCount": 2
},
{
"price": "1700000000000000000",
"size": "8000000000000000000",
"orderCount": 4
}
],
"timestamp": 1736409500000
}GET /markets/ticker/:symbol
Get 24-hour statistics and Greeks for a series.
Path Parameters:
Prop
Type
Response:
Prop
Type
Example:
curl "http://localhost:8080/markets/ticker/BTC-82000-C-1736409600"{
"symbol": "BTC-82000-C-1736409600",
"seriesId": "0x1a2b3c4d...",
"markPrice": "1500000000000000000",
"indexPrice": "81500000000000000000000",
"bestBid": "1450000000000000000",
"bestAsk": "1550000000000000000",
"delta": "550000000000000000",
"gamma": "12000000000000000",
"vega": "8500000000000000000",
"theta": "-250000000000000000",
"rho": "45000000000000000",
"iv": "650000000000000000",
"volume24h": "125000000000",
"trades24h": 47,
"priceChange24h": "5200000000000000000",
"high24h": "1600000000000000000",
"low24h": "1350000000000000000",
"openInterest": "50000000000000000000",
"lastTradeAt": 1736408900
}GET /markets/trades/:symbol
Get recent trades for a series.
Path Parameters:
Prop
Type
Query Parameters:
Prop
Type
Pagination: Use
beforewith the timestamp of the last trade to fetch older trades. Returns up tolimitresults (default 20, max 100).
Response:
Prop
Type
Trade Object:
Prop
Type
Example:
curl "http://localhost:8080/markets/trades/BTC-82000-C-1736409600?limit=5"{
"trades": [
{
"id": "trade_001",
"price": "1500000000000000000",
"size": "1000000000000000000",
"side": "buy",
"timestamp": 1736408900
},
{
"id": "trade_002",
"price": "1480000000000000000",
"size": "2500000000000000000",
"side": "sell",
"timestamp": 1736408800
}
],
"nextCursor": "1736408800"
}GET /markets/oracle/:pairId
Get oracle data for an underlying pair.
Path Parameters:
Prop
Type
Response:
Prop
Type
Example:
curl "http://localhost:8080/markets/oracle/0xabcd1234..."{
"pairId": "0xabcd1234...",
"symbol": "BTC-USDC",
"spotPrice": "81500000000000000000000",
"volatility": "650000000000000000",
"riskFreeRate": "50000000000000000",
"lastUpdate": 1736409000
}GET /markets/contracts
Get deployed contract addresses and ABIs.
Response:
Prop
Type
Example:
curl "http://localhost:8080/markets/contracts"{
"chainId": 10143,
"contracts": {
"DiffusalOracle": "0xa0d9da3a88e467e3a6a5a5666979a5784eb8d942",
"DiffusalOptionsQuoter": "0xd18b41918f5f5d943c26e58bd2bc5ede1ae03630",
"TestnetUSDC": "0xbdeaba226442621c7a9841a689284cfb1c4178e8",
"DiffusalOptionsPositionManager": "0xaacdabcc225b330f9f0d4b671138286b5d792288",
"DiffusalOptionsSeriesRegistry": "0xd880b541cf4d21635955d77cdb96498b4d937864",
"DiffusalCollateralVault": "0xc6fb31b62480eca5412bbe127d61aeb3c386fc25",
"DiffusalOptionsOrderBook": "0xcc064226992dd20de821200be8d3e612bf39d7d4",
"DiffusalOptionsRFQ": "0x560fcf29c95e775574ad44b5d50577f5a5c3d8a6"
}
}Use these addresses with the contract ABIs to interact with the protocol. See On-Chain Guide for contract interaction patterns.
GET /markets/open-interest
List open interest and caps for all trading pairs.
Response:
Prop
Type
Open Interest Object:
Prop
Type
Example:
curl "http://localhost:8080/markets/open-interest"{
"pairs": [
{
"pairId": "0xabcd1234...",
"symbol": "BTC-USDC",
"callOI": "50000000000000000000000",
"putOI": "35000000000000000000000",
"maxCallOI": "100000000000000000000000",
"maxPutOI": "100000000000000000000000",
"callsRemaining": "50000000000000000000000",
"putsRemaining": "65000000000000000000000"
},
{
"pairId": "0xef567890...",
"symbol": "ETH-USDC",
"callOI": "75000000000000000000000",
"putOI": "60000000000000000000000",
"maxCallOI": "200000000000000000000000",
"maxPutOI": "200000000000000000000000",
"callsRemaining": "125000000000000000000000",
"putsRemaining": "140000000000000000000000"
}
]
}Field Descriptions:
| Field | Description |
|---|---|
callOI | Total open interest for call options (WAD format, 18 decimals) |
putOI | Total open interest for put options (WAD format, 18 decimals) |
maxCallOI | Maximum allowed call OI set by MMM (0 = unlimited) |
maxPutOI | Maximum allowed put OI set by MMM (0 = unlimited) |
callsRemaining | Remaining capacity for new call positions |
putsRemaining | Remaining capacity for new put positions |
Note: Open interest is tracked at the pair level, aggregating all series (strikes and expiries) for that pair. This prevents users from bypassing caps by creating positions across different strikes.
GET /markets/open-interest/:pairId
Get open interest and caps for a specific trading pair.
Path Parameters:
Prop
Type
Response:
Prop
Type
Example:
curl "http://localhost:8080/markets/open-interest/0xabcd1234..."{
"data": {
"pairId": "0xabcd1234...",
"symbol": "BTC-USDC",
"callOI": "50000000000000000000000",
"putOI": "35000000000000000000000",
"maxCallOI": "100000000000000000000000",
"maxPutOI": "100000000000000000000000",
"callsRemaining": "50000000000000000000000",
"putsRemaining": "65000000000000000000000"
}
}Account Data (Auth Required)
These endpoints require authentication. Include the session cookie or JWT token.
GET /account/me
Get current user profile and aggregate metrics.
Response:
Prop
Type
Example:
curl "http://localhost:8080/account/me" \
-H "Cookie: session=..."{
"address": "0x742d35Cc6634C0532925a3b844Bc9e7595f1F321",
"portfolioCount": 2,
"totalEquity": "125000000000",
"totalDeposit": "100000000000",
"totalUnrealizedPnl": "25000000000",
"isHealthy": true,
"positionCount": 5
}GET /account/portfolios
List all user portfolios with summary data.
Response:
Prop
Type
Portfolio Summary:
Prop
Type
Example:
curl "http://localhost:8080/account/portfolios" \
-H "Cookie: session=..."{
"portfolios": [
{
"id": 1,
"positionCount": 3,
"equity": "75000000000",
"deposit": "60000000000",
"isHealthy": true,
"createdAt": 1736000000
},
{
"id": 2,
"positionCount": 2,
"equity": "50000000000",
"deposit": "40000000000",
"isHealthy": true,
"createdAt": 1736100000
}
]
}GET /account/portfolios/:id
Get detailed portfolio information with margin calculations.
Path Parameters:
Prop
Type
Response:
Prop
Type
Example:
curl "http://localhost:8080/account/portfolios/1" \
-H "Cookie: session=..."{
"id": 1,
"deposit": "60000000000",
"equity": "75000000000",
"unrealizedPnl": "15000000000",
"initialMargin": "20000000000",
"maintenanceMargin": "16000000000",
"maxWithdraw": "55000000000",
"isHealthy": true,
"isLiquidatable": false,
"healthRatio": "4687500000000000000",
"positionCount": 3
}GET /account/portfolios/:id/positions
Get all positions in a portfolio.
Path Parameters:
Prop
Type
Response:
Prop
Type
Position Object:
Prop
Type
Example:
curl "http://localhost:8080/account/portfolios/1/positions" \
-H "Cookie: session=..."{
"positions": [
{
"seriesId": "0x1a2b3c4d...",
"symbol": "BTC-82000-C-1736409600",
"optionBalance": "5000000000000000000",
"premiumBalance": "7500000000000000000",
"entryPrice": "1500000000000000000",
"realizedPnl": "0",
"markPrice": "1650000000000000000",
"notional": "407500000000",
"unrealizedPnl": "7500000000",
"delta": "2750000000000000000",
"gamma": "60000000000000000",
"vega": "42500000000000000000",
"theta": "-1250000000000000000"
}
]
}GET /account/portfolios/:id/collateral
Get collateral details for a portfolio.
Path Parameters:
Prop
Type
Response:
Prop
Type
Example:
curl "http://localhost:8080/account/portfolios/1/collateral" \
-H "Cookie: session=..."{
"deposit": "60000000000",
"maxWithdraw": "55000000000",
"locked": "5000000000"
}GET /account/orders
Get user's open orders across all portfolios.
Query Parameters:
Prop
Type
Response:
Prop
Type
Order Object:
Prop
Type
Example:
curl "http://localhost:8080/account/orders?portfolioId=1" \
-H "Cookie: session=..."{
"orders": [
{
"orderId": "0xorder123...",
"seriesId": "0x1a2b3c4d...",
"symbol": "BTC-82000-C-1736409600",
"portfolioId": 1,
"side": "buy",
"price": "1500000000000000000",
"size": "2000000000000000000",
"filled": "500000000000000000",
"remaining": "1500000000000000000",
"status": "partial",
"createdAt": 1736400000
}
]
}GET /account/trades
Get user's trade history.
Query Parameters:
Prop
Type
Pagination: Use
beforewith the trade ID fromnextCursorto fetch older trades. Returns up tolimitresults (default 20, max 100).
Response:
Prop
Type
User Trade Object:
Prop
Type
Example:
curl "http://localhost:8080/account/trades?portfolioId=1&limit=5" \
-H "Cookie: session=..."{
"trades": [
{
"id": "trade_abc123",
"seriesId": "0x1a2b3c4d...",
"symbol": "BTC-82000-C-1736409600",
"portfolioId": 1,
"side": "buy",
"price": "1500000000000000000",
"size": "1000000000000000000",
"fee": "150000",
"timestamp": 1736408900
}
],
"nextCursor": "trade_abc122"
}GET /account/fees
Get user's fee summary.
Response:
Prop
Type
Example:
curl "http://localhost:8080/account/fees" \
-H "Cookie: session=..."{
"totalFeesPaid": "1250000000",
"fees24h": "150000000",
"makerFees": "500000000",
"takerFees": "750000000",
"rebatesReceived": "100000000"
}Transaction Helpers
These endpoints help prepare transaction parameters. No authentication required.
GET /helpers/series-id
Compute series ID from parameters.
Query Parameters:
Prop
Type
Response:
Prop
Type
Example:
curl "http://localhost:8080/helpers/series-id?pairId=0xabcd...&strike=82000000000000000000000&expiry=1736409600&isCall=true"{
"seriesId": "0x1a2b3c4d5e6f..."
}GET /helpers/pair-id
Compute pair ID from pair name.
Query Parameters:
Prop
Type
Response:
Prop
Type
Example:
curl "http://localhost:8080/helpers/pair-id?name=BTC-USDC"{
"pairId": "0xabcd1234..."
}GET /helpers/tick-decimals/:pairId
Get current tick decimals for a pair.
Path Parameters:
Prop
Type
Response:
Prop
Type
Example:
curl "http://localhost:8080/helpers/tick-decimals/0xabcd1234..."{
"tickDecimals": 4,
"spotPrice": "81500000000000000000000"
}GET /helpers/tick-to-price
Convert tick to price.
Query Parameters:
Prop
Type
Response:
Prop
Type
Example:
curl "http://localhost:8080/helpers/tick-to-price?tick=15000&tickDecimals=4"{
"price": "1500000000000000000"
}GET /helpers/price-to-tick
Convert price to tick.
Query Parameters:
Prop
Type
Response:
Prop
Type
Example:
curl "http://localhost:8080/helpers/price-to-tick?price=1500000000000000000&tickDecimals=4&roundUp=false"{
"tick": "15000"
}POST /helpers/symbol/translate
Translate a symbol between Diffusal and user-facing formats.
Symbol Formats:
| Format | Pattern | Example |
|---|---|---|
| Diffusal | UNDERLYING-STRIKE-TYPE-EXPIRY | BTC-82000-C-1736409600 |
| User-facing | UNDERLYING-DDMMMYY-STRIKE-TYPE | BTC-09JAN26-82000-C |
Strikes support decimals using underscore (_) as separator:
ETH-3550_5-C-...= strike $3,550.50SHIB-0_00001234-C-...= strike $0.00001234
See Reference for complete examples covering all price ranges and edge cases.
Request Body:
Prop
Type
Response:
Prop
Type
Example - User-facing to Diffusal:
curl -X POST http://localhost:8080/helpers/symbol/translate \
-H "Content-Type: application/json" \
-d '{"symbol": "BTC-09JAN26-82000-C"}'Response:
{
"input": "BTC-09JAN26-82000-C",
"inputFormat": "external",
"output": "BTC-82000-C-1736409600",
"outputFormat": "diffusal"
}Example - Diffusal to User-facing:
curl -X POST http://localhost:8080/helpers/symbol/translate \
-H "Content-Type: application/json" \
-d '{"symbol": "BTC-82000-C-1736409600-SHORT"}'Response:
{
"input": "BTC-82000-C-1736409600-SHORT",
"inputFormat": "diffusal",
"output": "BTC-09JAN26-82000-C",
"outputFormat": "external",
"isShort": true
}Example - Decimal Strike:
curl -X POST http://localhost:8080/helpers/symbol/translate \
-H "Content-Type: application/json" \
-d '{"symbol": "ETH-3550_5-C-1736409600"}'Response:
{
"input": "ETH-3550_5-C-1736409600",
"inputFormat": "diffusal",
"output": "ETH-09JAN26-3550_5-C",
"outputFormat": "external"
}POST /helpers/symbol/translate/batch
Batch translate multiple symbols between formats.
Request Body:
Prop
Type
Response:
Prop
Type
Example:
curl -X POST http://localhost:8080/helpers/symbol/translate/batch \
-H "Content-Type: application/json" \
-d '{"symbols": ["BTC-09JAN26-82000-C", "ETH-82000-P-1736409600"]}'Response:
{
"results": [
{
"input": "BTC-09JAN26-82000-C",
"inputFormat": "external",
"output": "BTC-82000-C-1736409600",
"outputFormat": "diffusal"
},
{
"input": "ETH-82000-P-1736409600",
"inputFormat": "diffusal",
"output": "ETH-09JAN26-82000-P",
"outputFormat": "external"
}
],
"errors": []
}Error Responses
All endpoints return consistent error responses:
| HTTP Status | Description |
|---|---|
| 400 | Bad request (invalid parameters) |
| 401 | Unauthorized (auth required) |
| 403 | Forbidden (insufficient permissions) |
| 404 | Not found |
| 429 | Rate limited |
| 500 | Internal server error |
Error Response Format:
| Field | Type | Description |
|---|---|---|
error | string | Error code |
message | string | Human-readable message |
details | object | Additional error details (optional) |
Rate Limits
Rate limits vary based on authentication status. Authenticated users (with valid session) receive higher limits.
Unauthenticated Users (by IP)
| Endpoint Category | Rate Limit |
|---|---|
| Public market data | 60 req/min |
| Helpers | 100 req/min |
| Auth | 10 req/min |
Authenticated Users (by wallet address)
| Endpoint Category | Rate Limit |
|---|---|
| Public market data | 300 req/min |
| Helpers | 300 req/min |
| Account data | 120 req/min |
| Auth | 20 req/min |
Rate limit headers are exposed for future use. Currently, rate limit information is only available in 429 error responses.
Data Freshness
Understanding data update frequencies helps build responsive integrations:
| Data Type | Source | Update Frequency | Typical Latency |
|---|---|---|---|
| Orderbook | Indexed events | Real-time | ~1 block |
| Ticker / Greeks | Computed on request | Per request | Real-time |
| Oracle prices | On-chain oracle | ~30 seconds | 5-30s |
| Markets list | Indexed series data | ~60 seconds background refresh | ~1 min |
| Positions / Balances | Indexed events | Real-time | ~1-2 blocks |
| Trades | Indexed events | Real-time | ~1 block |
WebSocket vs REST
| Channel | Recommendation |
|---|---|
orderbook:* | Use WebSocket for live updates; REST for initial load |
ticker:* | Use WebSocket for price changes; REST for one-off queries |
trades:* | Use WebSocket for real-time fills; REST for history |
positions, collateral | WebSocket recommended for active trading |
Related
- WebSocket - Real-time data streams
- Authentication - SIWE flow details
- On-Chain Guide - Contract interactions