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:

base url
https://api.utxoiq.com

Overview

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 →
http
GET /api/v1/insights/latest HTTP/1.1
Host: api.utxoiq.com
X-API-Key: uiq_live_xxxxxxxxxxxxxxxxxxxx

Method 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.

bash
# 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

TierRequests / HourWebSocket
Free1001 connection
Pro1,0005 connections
Power10,000Unlimited

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

json
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests. Please slow down.",
    "details": { "retry_after": 42 }
  },
  "request_id": "req_01HXYZ..."
}
StatusCodeMeaning
400VALIDATION_ERRORInvalid request body / params
401UNAUTHORIZEDMissing or invalid credentials
402SUBSCRIPTION_REQUIREDFeature requires a paid plan
404NOT_FOUNDResource does not exist
429RATE_LIMIT_EXCEEDEDRequest quota exceeded
500INTERNAL_ERRORServer-side error
503DATA_UNAVAILABLEUpstream data not ready

REST API

All endpoints are under /api/v1

Auth

POST/api/v1/auth/register

Create account. Returns access_token + verification_token.

Public
POST/api/v1/auth/login

Email + password login. Returns access + refresh tokens.

Public
POST/api/v1/auth/refresh

Exchange refresh_token for a new access_token.

Public
POST/api/v1/auth/logout

Revoke current refresh token.

JWT / API Key
GET/api/v1/auth/profile

Get authenticated user profile.

JWT / API Key
PATCH/api/v1/auth/profile

Update display name, email preferences.

JWT / API Key
POST/api/v1/auth/forgot-password

Send password reset token.

Public
POST/api/v1/auth/reset-password

Set new password with reset token.

Public
POST/api/v1/auth/verify-email

Verify email with verification token.

Public

Insights

GET/api/v1/insights/latest

Latest AI-generated insights. Supports ?limit, ?category, ?min_confidence, ?signal_type.

JWT / API Key
GET/api/v1/insights/public

Public preview insights (no auth required, limited set).

Public
GET/api/v1/insights/{id}

Single insight by ID.

JWT / API Key
POST/api/v1/insights/{id}/feedback

Submit thumbs up/down feedback on an insight.

JWT / API Key

Signals & Feed

GET/api/v1/signals

Raw signal stream. Filter by ?signal_type, ?min_confidence, ?from, ?to.

JWT / API Key
GET/api/v1/signals/{id}

Single signal with full metadata.

JWT / API Key

Smart Money

GET/api/v1/smart-money/flows

Exchange net flow over time. ?days=7|30|90.

Pro+JWT / API Key
GET/api/v1/smart-money/whales

Large wallet movements above threshold.

Pro+JWT / API Key
GET/api/v1/smart-money/miners

Miner treasury balances and sell pressure.

Pro+JWT / API Key

Entities

GET/api/v1/entities

Known Bitcoin entities (exchanges, miners, treasuries). Paginated.

JWT / API Key
GET/api/v1/entities/{id}

Entity detail with balance history and recent signals.

JWT / API Key
GET/api/v1/labels

Community address labels.

JWT / API Key

Alerts

GET/api/v1/alerts

List your alert rules.

JWT / API Key
POST/api/v1/alerts

Create alert rule. Body: signal_type, min_confidence, conditions.

JWT / API Key
GET/api/v1/alerts/{id}

Single alert rule.

JWT / API Key
PUT/api/v1/alerts/{id}

Update alert rule.

JWT / API Key
DELETE/api/v1/alerts/{id}

Delete alert rule.

JWT / API Key

Daily Brief

GET/api/v1/brief/today

Today's AI-curated brief: top insights per signal category.

JWT / API Key
GET/api/v1/brief/history

Previous daily briefs. ?days=7.

Pro+JWT / API Key

Search

GET/api/v1/search

Search by address, txid, block height, or entity name. ?q=...&type=address|txid|block|entity.

JWT / API Key
GET/api/v1/search/suggestions

Typeahead suggestions for entity names.

JWT / API Key

Billing

GET/api/v1/billing/subscription

Current user's subscription info and tier.

JWT
GET/api/v1/billing/config

Stripe publishable key and plan configuration.

Public
POST/api/v1/billing/checkout

Start Stripe Checkout session. Body: { tier: 'pro' | 'power' }.

JWT
POST/api/v1/billing/portal

Open Stripe Customer Portal for payment management.

JWT
POST/api/v1/billing/cancel

Set subscription to cancel at period end.

JWT
POST/api/v1/billing/webhook

Stripe webhook endpoint (Stripe → server only).

Public

API Keys

GET/api/v1/auth/api-keys

List your API keys.

JWT
POST/api/v1/auth/api-keys

Create API key. Body: { name, scopes }.

JWT
DELETE/api/v1/auth/api-keys/{key_id}

Revoke an API key.

JWT

Health

GET/health

Service health check. Returns status of DB, Redis, BigQuery, ingestion.

Public
GET/api/v1/monitoring/status

Detailed system status with block rate and signal metrics.

Public

Example: Fetch latest insights

bash
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

javascript
// 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

javascript
// 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 timestamp
insightNew insight available — full insight object in data field
heartbeatServer ping every 30s — reply with { "type": "pong" }
errorAuthentication or subscription error — connection will close

Python SDK

pip install utxoiq — Python 3.9+

Installation

bash
pip install utxoiq

API Key authentication

python
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

python
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

python
# 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

python
# 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

python
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

python
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

bash
npm install @utxoiq/sdk

API Key authentication

typescript
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

typescript
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

typescript
// 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

typescript
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

typescript
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

typescript
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.

bash
# 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 interpretation
researcherTechnical blockchain research — academic framing
traderSignal interpretation for trading decisions
defaultGeneral assistant with live Bitcoin context
bash
# 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