Developer Docs
utxoIQ API Reference
Real-time Bitcoin on-chain intelligence via REST, WebSocket, and native SDKs. All responses are JSON. The base URL for all API endpoints is:
https://api.utxoiq.comOverview
Key concepts and API design
utxoIQ processes raw Bitcoin blocks in real-time, classifies on-chain behaviour into typed signals (mempool pressure, exchange flows, miner treasury, whale accumulation), and surfaces AI-generated insights via a RESTful API and live WebSocket stream.
Versioned
All endpoints under /api/v1
JSON
Request and response bodies
Bearer + API Key
Two auth methods supported
Authentication
Two methods: JWT Bearer tokens (user sessions) or API Keys (server-to-server)
Method 1 — API Key
Generate API keys from your profile. Pass them via the X-API-Key header.
API keys are available on all plans.
Sign up free →GET /api/v1/insights/latest HTTP/1.1
Host: api.utxoiq.com
X-API-Key: uiq_live_xxxxxxxxxxxxxxxxxxxxMethod 2 — JWT Bearer (Login)
Authenticate with email/password to receive short-lived access tokens (15 min) and long-lived refresh tokens (7 days). Access tokens are passed as Bearer credentials.
# 1. Login — obtain tokens
curl -X POST https://api.utxoiq.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "password": "yourpassword"}'
# Response:
# { "access_token": "eyJ...", "refresh_token": "rt_...", "token_type": "bearer", "expires_in": 900 }
# 2. Use the access token
curl https://api.utxoiq.com/api/v1/insights/latest \
-H "Authorization: Bearer eyJ..."
# 3. Refresh before expiry
curl -X POST https://api.utxoiq.com/api/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refresh_token": "rt_..."}'Security note: Never store access tokens in localStorage. Keep them in memory and rotate using the refresh endpoint 60 seconds before expiry.
Rate Limits
Limits are per user per rolling hour
Rate limit headers are included in every response: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset. Exceeded limits return HTTP 429.
Error Handling
Consistent error envelope across all endpoints
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please slow down.",
"details": { "retry_after": 42 }
},
"request_id": "req_01HXYZ..."
}400VALIDATION_ERRORInvalid request body / params401UNAUTHORIZEDMissing or invalid credentials402SUBSCRIPTION_REQUIREDFeature requires a paid plan404NOT_FOUNDResource does not exist429RATE_LIMIT_EXCEEDEDRequest quota exceeded500INTERNAL_ERRORServer-side error503DATA_UNAVAILABLEUpstream data not readyREST API
All endpoints are under /api/v1
Auth
/api/v1/auth/registerCreate account. Returns access_token + verification_token.
/api/v1/auth/loginEmail + password login. Returns access + refresh tokens.
/api/v1/auth/refreshExchange refresh_token for a new access_token.
/api/v1/auth/logoutRevoke current refresh token.
/api/v1/auth/profileGet authenticated user profile.
/api/v1/auth/profileUpdate display name, email preferences.
/api/v1/auth/forgot-passwordSend password reset token.
/api/v1/auth/reset-passwordSet new password with reset token.
/api/v1/auth/verify-emailVerify email with verification token.
Insights
/api/v1/insights/latestLatest AI-generated insights. Supports ?limit, ?category, ?min_confidence, ?signal_type.
/api/v1/insights/publicPublic preview insights (no auth required, limited set).
/api/v1/insights/{id}Single insight by ID.
/api/v1/insights/{id}/feedbackSubmit thumbs up/down feedback on an insight.
Signals & Feed
/api/v1/signalsRaw signal stream. Filter by ?signal_type, ?min_confidence, ?from, ?to.
/api/v1/signals/{id}Single signal with full metadata.
Smart Money
/api/v1/smart-money/flowsExchange net flow over time. ?days=7|30|90.
/api/v1/smart-money/whalesLarge wallet movements above threshold.
/api/v1/smart-money/minersMiner treasury balances and sell pressure.
Entities
/api/v1/entitiesKnown Bitcoin entities (exchanges, miners, treasuries). Paginated.
/api/v1/entities/{id}Entity detail with balance history and recent signals.
/api/v1/labelsCommunity address labels.
Alerts
/api/v1/alertsList your alert rules.
/api/v1/alertsCreate alert rule. Body: signal_type, min_confidence, conditions.
/api/v1/alerts/{id}Single alert rule.
/api/v1/alerts/{id}Update alert rule.
/api/v1/alerts/{id}Delete alert rule.
Daily Brief
/api/v1/brief/todayToday's AI-curated brief: top insights per signal category.
/api/v1/brief/historyPrevious daily briefs. ?days=7.
Search
/api/v1/searchSearch by address, txid, block height, or entity name. ?q=...&type=address|txid|block|entity.
/api/v1/search/suggestionsTypeahead suggestions for entity names.
Billing
/api/v1/billing/subscriptionCurrent user's subscription info and tier.
/api/v1/billing/configStripe publishable key and plan configuration.
/api/v1/billing/checkoutStart Stripe Checkout session. Body: { tier: 'pro' | 'power' }.
/api/v1/billing/portalOpen Stripe Customer Portal for payment management.
/api/v1/billing/cancelSet subscription to cancel at period end.
/api/v1/billing/webhookStripe webhook endpoint (Stripe → server only).
API Keys
/api/v1/auth/api-keysList your API keys.
/api/v1/auth/api-keysCreate API key. Body: { name, scopes }.
/api/v1/auth/api-keys/{key_id}Revoke an API key.
Health
/healthService health check. Returns status of DB, Redis, BigQuery, ingestion.
/api/v1/monitoring/statusDetailed system status with block rate and signal metrics.
Example: Fetch latest insights
curl "https://api.utxoiq.com/api/v1/insights/latest?limit=5&min_confidence=0.7" \
-H "X-API-Key: uiq_live_xxxxxxxxxxxxxxxxxxxx"
# Response
{
"insights": [
{
"id": "01HXYZ...",
"signal_type": "whale",
"headline": "Large accumulation detected — 2,400 BTC moved to cold storage",
"summary": "A cluster of wallets linked to long-term holders...",
"confidence": 0.91,
"timestamp": "2026-04-04T09:12:00Z",
"block_height": 894210,
"tags": ["accumulation", "cold-storage"],
"is_predictive": false,
"chart_url": null
}
],
"total": 1,
"page": 1,
"limit": 5
}WebSocket
Real-time insight and system monitoring streams
Insight Feed
// Connect with JWT token as query param
const ws = new WebSocket(
'wss://api.utxoiq.com/ws/insights?token=eyJ...'
);
ws.onopen = () => console.log('Connected to insight feed');
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
// msg.type: "insight" | "heartbeat" | "connected"
if (msg.type === 'insight') {
const { id, signal_type, headline, confidence } = msg.data;
console.log(`[${signal_type}] ${headline} — ${confidence}`);
}
};
// Heartbeat — reply to keep connection alive
ws.addEventListener('message', (e) => {
const msg = JSON.parse(e.data);
if (msg.type === 'heartbeat') ws.send(JSON.stringify({ type: 'pong' }));
});Monitoring Stream
// No auth required — public system status
const ws = new WebSocket('wss://api.utxoiq.com/ws/monitoring');
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
// { block_height, mempool_size, ingestion_lag_ms, active_connections }
};WebSocket Message Types
connectedSent on successful connection with server timestampinsightNew insight available — full insight object in data fieldheartbeatServer ping every 30s — reply with { "type": "pong" }errorAuthentication or subscription error — connection will closePython SDK
pip install utxoiq — Python 3.9+
Installation
pip install utxoiqAPI Key authentication
from utxoiq import UtxoIQClient
client = UtxoIQClient(api_key="uiq_live_xxxxxxxxxxxxxxxxxxxx")
# Fetch latest insights
insights = client.insights.get_latest(limit=10, min_confidence=0.7)
for insight in insights:
print(f"[{insight.signal_type}] {insight.headline} — {insight.confidence:.0%}")Email / Password login
client = UtxoIQClient()
client.login(email="you@example.com", password="yourpassword")
# Tokens stored in memory; auto-refreshed before expiry
profile = client.get("/api/v1/auth/profile").json()
print(profile["email"])Signals and Smart Money
# Get smart money exchange flows (Pro+)
flows = client.get(
"/api/v1/smart-money/flows",
params={"days": 30}
).json()
# Whale movements
whales = client.get(
"/api/v1/smart-money/whales",
params={"min_amount_btc": 100}
).json()Alerts CRUD
# Create a whale alert
alert = client.alerts.create({
"name": "Big whale move",
"signal_type": "whale",
"min_confidence": 0.85,
"conditions": {"min_amount_btc": 500}
})
print(f"Alert created: {alert['id']}")
# List alerts
alerts = client.alerts.list()
for a in alerts:
print(f" - {a['name']} ({a['status']})")
# Delete
client.alerts.delete(alert["id"])Daily Brief
brief = client.daily_brief.get_today()
print(brief["summary"])
for category, items in brief["by_category"].items():
print(f"\n{category.upper()}")
for item in items:
print(f" • {item['headline']}")Error handling
from utxoiq import UtxoIQClient
from utxoiq.exceptions import (
AuthenticationError,
RateLimitError,
SubscriptionRequiredError,
NotFoundError,
)
import time
client = UtxoIQClient(api_key="uiq_live_xxxxxxxxxxxxxxxxxxxx")
try:
insights = client.insights.get_latest(limit=50)
except AuthenticationError:
print("Invalid API key")
except RateLimitError as e:
print(f"Rate limited — retry in {e.retry_after}s")
time.sleep(e.retry_after or 60)
except SubscriptionRequiredError:
print("This feature requires a Pro or Power plan")
except NotFoundError:
print("Resource not found")JavaScript / TypeScript SDK
npm install @utxoiq/sdk — Node.js 18+ and modern browsers
Installation
npm install @utxoiq/sdkAPI Key authentication
import { UtxoIQClient } from '@utxoiq/sdk';
const client = new UtxoIQClient({ apiKey: 'uiq_live_xxxxxxxxxxxxxxxxxxxx' });
const insights = await client.insights.getLatest({ limit: 10, minConfidence: 0.7 });
insights.forEach(({ signalType, headline, confidence }) =>
console.log(`[${signalType}] ${headline} — ${(confidence * 100).toFixed(0)}%`)
);Login and token refresh
const client = new UtxoIQClient();
await client.login('you@example.com', 'yourpassword');
// Tokens stored in memory; Axios interceptor auto-refreshes on 401
const profile = await client.get('/api/v1/auth/profile');
console.log(profile.data.email);Alerts
// Create
const alert = await client.alerts.create({
name: 'Mempool spike',
signal_type: 'mempool',
min_confidence: 0.8,
conditions: { fee_rate_threshold: 50 },
});
// List
const { alerts } = await client.alerts.list();
// Update
await client.alerts.update(alert.id, { min_confidence: 0.9 });
// Delete
await client.alerts.delete(alert.id);WebSocket real-time feed
import { RealtimeWebSocket } from '@utxoiq/sdk';
const ws = new RealtimeWebSocket({
baseUrl: 'wss://api.utxoiq.com',
token: accessToken, // JWT access token
onInsight: (insight) => {
console.log('[New insight]', insight.headline);
},
onError: (err) => console.error('WS error:', err),
autoReconnect: true, // reconnect on disconnect
});
ws.connect();
// Later:
ws.disconnect();SSE streaming chat
import { StreamingChat } from '@utxoiq/sdk';
const stream = new StreamingChat({
baseUrl: 'https://api.utxoiq.com',
apiKey: 'uiq_live_xxxxxxxxxxxxxxxxxxxx',
});
await stream.query({
message: 'What does the current mempool data suggest about fee pressure?',
role: 'analyst',
onToken: (token) => process.stdout.write(token),
onDone: () => console.log('\nStream complete'),
});Error handling
import {
UtxoIQError,
AuthenticationError,
RateLimitError,
SubscriptionRequiredError,
} from '@utxoiq/sdk';
try {
const insights = await client.insights.getLatest({ limit: 50 });
} catch (err) {
if (err instanceof AuthenticationError) {
console.error('Invalid credentials');
} else if (err instanceof RateLimitError) {
const delay = (err.retryAfter ?? 60) * 1000;
console.error(`Rate limited — retrying in ${delay}ms`);
await new Promise(r => setTimeout(r, delay));
} else if (err instanceof SubscriptionRequiredError) {
console.error('Upgrade required for this feature');
} else if (err instanceof UtxoIQError) {
console.error(`API error [${err.statusCode}]: ${err.message}`);
}
}AI Chat
Conversational Bitcoin intelligence — streamed via Server-Sent Events
The chat endpoint accepts a message and optional role, provider, and model parameters. The server injects live Bitcoin context (latest block, fee rates, top signals) into the system prompt.
# Streaming chat request (SSE)
curl -X POST https://api.utxoiq.com/api/v1/chat/query \
-H "X-API-Key: uiq_live_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"message": "Is now a good time to transact on-chain?",
"role": "analyst",
"provider": "anthropic",
"model": "claude-sonnet-4-6"
}'Available Roles
analystBitcoin market analysis and on-chain data interpretationresearcherTechnical blockchain research — academic framingtraderSignal interpretation for trading decisionsdefaultGeneral assistant with live Bitcoin context# List providers and models
curl https://api.utxoiq.com/api/v1/chat/providers \
-H "X-API-Key: uiq_live_xxxxxxxxxxxxxxxxxxxx"
# List roles
curl https://api.utxoiq.com/api/v1/chat/roles \
-H "X-API-Key: uiq_live_xxxxxxxxxxxxxxxxxxxx"utxoIQ
Bitcoin intelligence API