Authentication
All Aleatoric Data feeds require API key authentication. This page covers the security model, protocol-specific authentication methods, key scopes, rate limits, and key rotation procedures.
Account Registration
Section titled “Account Registration”You must register an Aleatoric account before any authenticated Data or MCP
request will succeed. Discovery endpoints such as /.well-known/mcp.json are
public, but JSON-RPC, gRPC, SSE, and MCP tool calls require a provisioned
ak_live_... key.
The same account and API key are valid across both public Aleatoric surfaces:
data.aleatoric.systemsfor live data feeds and the app consolesim.aleatoric.systems/mcp.aleatoric.systemsfor deterministic simulation and MCP access
Registration and login flows now persist registration and auth metadata,
including source attribution such as web, smithery_mcp, lobrunner, and
UTM/referrer context when provided.
Authentication Flow
Section titled “Authentication Flow”Authentication is performed at the Aleatoric service edge before requests are admitted to the data plane.
HMAC-SHA256 Key Verification
Section titled “HMAC-SHA256 Key Verification”Aleatoric never stores your API key in plaintext. When you create a key, the system computes an HMAC-SHA256 hash and stores only the hash. On every request, the same operation is performed on the submitted key and compared against the stored value.
The verification function is:
where:
- is the API key transmitted in the request (e.g.,
ak_live_c51nSdWI9ms...) - is a server-side secret that is never exposed to clients
- is the stored hash used for constant-time comparison
The verification is performed at the gateway layer before any request reaches the data plane. Timing-safe comparison prevents side-channel attacks:
Security properties — The HMAC construction ensures that even if the hash store is compromised, an attacker cannot derive valid API keys without possession of . Key hashes are cached in-process with a 5-minute TTL to minimize lookup latency.
Protocol-Specific Authentication
Section titled “Protocol-Specific Authentication”Each transport protocol accepts API keys through specific mechanisms:
| Protocol | Authentication Method | Header / Field |
|---|---|---|
| JSON-RPC (HTTPS) | HTTP header | x-api-key: ak_live_... |
| gRPC (HTTP/2) | Metadata entry | x-api-key: ak_live_... or authorization: Bearer ak_live_... |
| Unified Stream (SSE) | HTTP header | x-api-key: ak_live_... or Authorization: Bearer ak_live_... |
| Disk-Sync WebSocket | Header or query param | x-api-key header or ?api_key=ak_live_... query parameter |
JSON-RPC
Section titled “JSON-RPC”Pass the key as an x-api-key header on every HTTP POST:
curl -s -X POST https://rpc.aleatoric.systems \ -H "Content-Type: application/json" \ -H "x-api-key: ak_live_YOUR_KEY_HERE" \ -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'Attach the key as gRPC metadata. Both x-api-key and authorization metadata keys are accepted:
import grpc
channel = grpc.secure_channel( "hl.grpc.aleatoric.systems:443", grpc.ssl_channel_credentials(),)stub = PriceServiceStub(channel)
# Option 1: x-api-key metadataresponse = stub.GetMidPrice( MidPriceRequest(coin="BTC"), metadata=[("x-api-key", "ak_live_YOUR_KEY_HERE")],)
# Option 2: Bearer token metadataresponse = stub.GetMidPrice( MidPriceRequest(coin="BTC"), metadata=[("authorization", "Bearer ak_live_YOUR_KEY_HERE")],)For persistent streaming RPCs, the metadata is sent once at stream initiation and remains valid for the lifetime of the connection.
Unified Stream (SSE)
Section titled “Unified Stream (SSE)”Pass the key as an HTTP header when opening the SSE connection:
# x-api-key headercurl -N -H "x-api-key: ak_live_YOUR_KEY_HERE" \ "https://unified.grpc.aleatoric.systems/api/v1/unified/stream"
# Bearer tokencurl -N -H "Authorization: Bearer ak_live_YOUR_KEY_HERE" \ "https://unified.grpc.aleatoric.systems/api/v1/unified/stream"Disk-Sync WebSocket
Section titled “Disk-Sync WebSocket”WebSocket connections accept the key either as a header during the upgrade handshake or as a query parameter:
// Query parameter (when headers are not available, e.g., browser WebSocket API)const ws = new WebSocket( 'wss://disk.grpc.aleatoric.systems?api_key=ak_live_YOUR_KEY_HERE');
ws.onopen = () => console.log('Connected to Disk-Sync');ws.onmessage = (msg) => console.log(JSON.parse(msg.data));import websockets
# Header-based auth (preferred in server-side clients)async with websockets.connect( "wss://disk.grpc.aleatoric.systems", extra_headers={"x-api-key": "ak_live_YOUR_KEY_HERE"},) as ws: async for message in ws: print(message)Security note — When using query parameter authentication, the key may appear in server access logs and browser history. Use header-based authentication whenever possible.
Key Scopes
Section titled “Key Scopes”API keys can be scoped to restrict access to specific services and regions. Scopes are configured when creating or editing a key in App Console > API Keys.
| Scope | Description | Example |
|---|---|---|
chain:hyperliquid | Access to Hyperliquid L1 feeds only | Restrict keys to a single chain |
region:us | US region endpoints only | region:jp for Japan-only access |
stream:read | Unified Stream read access | Required for SSE event subscriptions |
status:read | Status API read access | Health checks, uptime monitoring |
status:admin | Status API admin access | Incident management, maintenance windows |
Scopes follow an additive model. A key with no explicit scopes defaults to full access for its tier. Adding scopes restricts the key to only those permissions:
Rate Limits
Section titled “Rate Limits”Rate limits are enforced per API key at the gateway layer. Exceeding the limit returns HTTP 429 Too Many Requests (JSON-RPC / SSE) or gRPC status RESOURCE_EXHAUSTED.
| Tier | Requests / minute | Requests / second | Burst Allowance |
|---|---|---|---|
| Basic | 100 | 2 | 5 req burst |
| Pro | 120,000 | 2,000 | 500 req burst |
| Quant | Unlimited | Unlimited | N/A |
The rate limiter uses a token bucket algorithm. For a given tier with rate requests/second and burst capacity :
A request is admitted if , in which case one token is consumed. Otherwise, the request is rejected with a Retry-After header indicating the wait time in seconds.
For streaming protocols (gRPC server-streaming, SSE), the rate limit applies to connection initiation, not to individual messages within an established stream.
See Rate Limits for detailed per-endpoint limits, retry strategies, and backoff recommendations.
Key Rotation
Section titled “Key Rotation”Keys can be rotated from App Console > API Keys with zero downtime using the following procedure:
Step 1: Create a New Key
Section titled “Step 1: Create a New Key”Navigate to Dashboard > API Keys > Create Key. The new key is immediately active alongside your existing key. Both keys will work simultaneously.
Step 2: Update Your Clients
Section titled “Step 2: Update Your Clients”Deploy the new key to all clients. For rolling deployments, the overlap window ensures no requests are rejected:
# Update environment variableexport ALEATORIC_API_KEY="ak_live_NEW_KEY_HERE"
# Verify the new key workscurl -s -X POST https://rpc.aleatoric.systems \ -H "Content-Type: application/json" \ -H "x-api-key: $ALEATORIC_API_KEY" \ -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'Step 3: Revoke the Old Key
Section titled “Step 3: Revoke the Old Key”Once all clients are updated, revoke the old key from Dashboard > API Keys > Revoke. Revocation is immediate and irreversible. Any in-flight requests using the old key will receive a 401 Unauthorized response.
Best practice — Rotate keys on a regular schedule (e.g., every 90 days) and immediately after any suspected compromise. The app console shows the last-used timestamp for each key to help identify unused keys.
Error Responses
Section titled “Error Responses”| HTTP Status | gRPC Status | Meaning |
|---|---|---|
401 Unauthorized | UNAUTHENTICATED | Missing, invalid, or revoked API key |
403 Forbidden | PERMISSION_DENIED | Key lacks required scope for the requested resource |
429 Too Many Requests | RESOURCE_EXHAUSTED | Rate limit exceeded; check Retry-After header |
See Error Codes for the complete error reference.