Complete REST API documentation for the Hyperliquid TWAP Data Service.
Version: Production-Ready v2.0
http://localhost:8000 # Development
https://api.yourdomain.com # Production
When the API server is running:
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc
- OpenAPI JSON: http://localhost:8000/openapi.json
GET /healthz
Check service health and database connectivity.
Parameters: None
Response:
{
"status": "healthy",
"database": "connected",
"last_ingested_object": "local:tests/data/sample_twap.parquet",
"last_ingested_at": "2025-11-04T12:00:00Z"
}Example:
curl http://localhost:8000/healthzGET /api/v1/twaps
Query TWAPs by wallet address and time range with optional filtering.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
wallet |
string | ✅ Yes | - | Wallet address |
start |
datetime | ✅ Yes | - | Start timestamp (ISO8601) |
end |
datetime | ✅ Yes | - | End timestamp (ISO8601) |
asset |
string | ❌ No | - | Filter by asset/coin (e.g., "SOL", "ETH") |
latest_per_twap |
boolean | ❌ No | true |
Return only latest row per TWAP ID |
limit |
integer | ❌ No | 500 |
Maximum number of TWAPs (1-5000) |
offset |
integer | ❌ No | 0 |
Number of TWAPs to skip (pagination) |
{
"wallet": "0xabc123def456",
"start": "2025-11-01T00:00:00Z",
"end": "2025-11-04T00:00:00Z",
"twaps": [
{
"twap_id": "123456",
"asset": "SOL",
"side": "B",
"status": "completed",
"duration_minutes": 30,
"latest_ts": "2025-11-03T12:30:00Z",
"executed": {
"size": "100.0",
"notional": "9050.00"
},
"raw": {}
}
]
}wallet- Wallet address queriedstart- Start timestampend- End timestamptwaps[]- Array of TWAP objectstwap_id- Unique TWAP identifierasset- Asset/coin symbolside- "B" (Buy) or "A" (Ask/Sell)status- TWAP status (e.g., "completed", "executing", "cancelled")duration_minutes- TWAP duration in minuteslatest_ts- Timestamp of latest status updateexecuted.size- Executed size (string decimal)executed.notional- Executed notional value (string decimal)raw- Raw parquet payload (JSONB)
Basic Query:
curl "http://localhost:8000/api/v1/twaps?wallet=0xabc123def456&start=2025-11-01T00:00:00Z&end=2025-11-04T00:00:00Z"With Asset Filter:
curl "http://localhost:8000/api/v1/twaps?wallet=0xabc123def456&start=2025-11-01T00:00:00Z&end=2025-11-04T00:00:00Z&asset=SOL"With Pagination (Page 1):
curl "http://localhost:8000/api/v1/twaps?wallet=0xabc123def456&start=2025-11-01T00:00:00Z&end=2025-11-04T00:00:00Z&limit=100&offset=0"With Pagination (Page 2):
curl "http://localhost:8000/api/v1/twaps?wallet=0xabc123def456&start=2025-11-01T00:00:00Z&end=2025-11-04T00:00:00Z&limit=100&offset=100"All Status Updates:
curl "http://localhost:8000/api/v1/twaps?wallet=0xabc123def456&start=2025-11-01T00:00:00Z&end=2025-11-04T00:00:00Z&latest_per_twap=false"GET /api/v1/twaps/{twap_id}
Get all status update rows for a specific TWAP ID.
| Parameter | Type | Required | Description |
|---|---|---|---|
twap_id |
string | ✅ Yes | TWAP identifier |
{
"twap_id": "123456",
"rows": [
{
"wallet": "0xabc123def456",
"ts": "2025-11-03T12:30:00Z",
"asset": "SOL",
"side": "B",
"size_requested": "100.0",
"size_executed": "100.0",
"notional_executed": "9050.00",
"status": "completed",
"duration_minutes": 30,
"raw": {}
},
{
"wallet": "0xabc123def456",
"ts": "2025-11-03T12:15:00Z",
"asset": "SOL",
"side": "B",
"size_requested": "100.0",
"size_executed": "25.8",
"notional_executed": "2332.20",
"status": "executing",
"duration_minutes": 30,
"raw": {}
}
]
}twap_id- TWAP identifierrows[]- Array of status updates (newest first)wallet- Wallet addressts- Timestamp of this status updateasset- Asset/coin symbolside- "B" (Buy) or "A" (Ask/Sell)size_requested- Requested size (string decimal)size_executed- Executed size at this timestamp (string decimal)notional_executed- Executed notional value (string decimal)status- Status at this timestampduration_minutes- TWAP durationraw- Raw parquet payload (JSONB)
curl http://localhost:8000/api/v1/twaps/123456404 Not Found:
{
"detail": "TWAP ID 123456 not found"
}GET /metrics
Get Prometheus-formatted metrics for monitoring.
Parameters: None
Response: Plain text (Prometheus format)
# HELP api_requests_total Total number of API requests
# TYPE api_requests_total counter
api_requests_total{endpoint="GET /api/v1/twaps"} 42
api_requests_total{endpoint="GET /healthz"} 15
# HELP api_request_duration_seconds API request duration
# TYPE api_request_duration_seconds summary
api_request_duration_seconds_count{endpoint="GET /api/v1/twaps"} 42
api_request_duration_seconds_sum{endpoint="GET /api/v1/twaps"} 1.234
api_request_duration_seconds{endpoint="GET /api/v1/twaps",quantile="0.5"} 0.025
api_request_duration_seconds{endpoint="GET /api/v1/twaps",quantile="0.95"} 0.100
api_request_duration_seconds{endpoint="GET /api/v1/twaps",quantile="0.99"} 0.250
# HELP etl_runs_total Total number of ETL runs
# TYPE etl_runs_total counter
etl_runs_total 15
# HELP etl_failures_total Total number of ETL failures
# TYPE etl_failures_total counter
etl_failures_total 0
# HELP etl_last_run_timestamp Unix timestamp of last ETL run
# TYPE etl_last_run_timestamp gauge
etl_last_run_timestamp 1730736000.0
api_requests_total- Total API requests by endpointapi_request_duration_seconds- Request duration (count, sum, p50, p95, p99)etl_runs_total- Total ETL runsetl_failures_total- Failed ETL runsetl_last_run_timestamp- Last ETL run timestamp (Unix time)
curl http://localhost:8000/metricsGET /
Get basic service information.
Parameters: None
Response:
{
"service": "Hyperliquid TWAP Data Service",
"version": "0.1.0",
"docs": "/docs",
"health": "/healthz",
"metrics": "/metrics"
}Example:
curl http://localhost:8000/All endpoints may return these error responses:
Invalid query parameters or request format.
{
"detail": [
{
"loc": ["query", "start"],
"msg": "field required",
"type": "value_error.missing"
}
]
}Resource not found (e.g., TWAP ID doesn't exist).
{
"detail": "TWAP ID 123456 not found"
}Database or internal server error.
{
"detail": "Internal server error"
}Currently no rate limiting is enforced. For production deployments, consider adding rate limiting via:
- API Gateway (AWS API Gateway, Kong, etc.)
- Nginx
limit_reqmodule - Application-level middleware
CORS is enabled and configurable via the CORS_ORIGINS environment variable:
# Allow all origins (development)
CORS_ORIGINS="*"
# Allow specific origins (production)
CORS_ORIGINS="https://app.example.com,https://dashboard.example.com"Allowed methods: GET, POST, PUT, DELETE, OPTIONS
Allowed headers: All
Currently no authentication is required. For production deployments, consider adding:
- API key authentication
- JWT tokens
- OAuth 2.0
- Mutual TLS
Example with API key header:
curl -H "X-API-Key: your-api-key" http://localhost:8000/api/v1/twaps?...import requests
from datetime import datetime
class HyperliquidTWAPClient:
def __init__(self, base_url="http://localhost:8000"):
self.base_url = base_url
def get_twaps(self, wallet, start, end, asset=None, limit=500, offset=0):
"""Query TWAPs by wallet and time range."""
params = {
"wallet": wallet,
"start": start.isoformat(),
"end": end.isoformat(),
"limit": limit,
"offset": offset,
}
if asset:
params["asset"] = asset
response = requests.get(f"{self.base_url}/api/v1/twaps", params=params)
response.raise_for_status()
return response.json()
def get_twap_by_id(self, twap_id):
"""Get all rows for a specific TWAP."""
response = requests.get(f"{self.base_url}/api/v1/twaps/{twap_id}")
response.raise_for_status()
return response.json()
# Usage
client = HyperliquidTWAPClient()
twaps = client.get_twaps(
wallet="0xabc123def456",
start=datetime(2025, 11, 1),
end=datetime(2025, 11, 4),
asset="SOL"
)
print(f"Found {len(twaps['twaps'])} TWAPs")class HyperliquidTWAPClient {
constructor(baseUrl = 'http://localhost:8000') {
this.baseUrl = baseUrl;
}
async getTWAPs(wallet, start, end, options = {}) {
const params = new URLSearchParams({
wallet,
start: start.toISOString(),
end: end.toISOString(),
limit: options.limit || 500,
offset: options.offset || 0,
});
if (options.asset) params.append('asset', options.asset);
const response = await fetch(`${this.baseUrl}/api/v1/twaps?${params}`);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
}
async getTWAPById(twapId) {
const response = await fetch(`${this.baseUrl}/api/v1/twaps/${twapId}`);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
}
}
// Usage
const client = new HyperliquidTWAPClient();
const twaps = await client.getTWAPs(
'0xabc123def456',
new Date('2025-11-01'),
new Date('2025-11-04'),
{ asset: 'SOL' }
);
console.log(`Found ${twaps.twaps.length} TWAPs`);- Use pagination for large result sets to avoid timeouts
- Cache responses when appropriate (data doesn't change frequently)
- Handle errors gracefully with exponential backoff for retries
- Validate timestamps are in ISO8601 format with timezone
- Monitor metrics endpoint for system health
💰 Cost Note: High-volume queries may increase database load. For large date ranges, use pagination. See ../README.md#-cost-considerations for optimization tips.
Query optimization:
- Use specific date ranges (avoid full-year queries)
- Set
latest_per_twap=trueto reduce result size - Use pagination (
limit+offset) for results > 1000 records - Filter by
assetwhen possible