SatsAPI Documentation
SatsAPI is a Bitcoin market intelligence API that uses the Lightning Network L402 protocol for pay-per-call pricing. No registration, no API keys, no subscriptions. You pay in satoshis, you get data.
The API provides 8 endpoints covering real-time price data, mempool analysis, on-chain metrics, derivatives, AI-generated signals and full market summaries. Every response is structured for both human developers and autonomous AI agents.
Base URL
https://satsapi.dev
All endpoints are served over HTTPS. HTTP requests are redirected to HTTPS.
Quick Start
Three steps to get data. No setup, no account:
# Step 1 — request returns 402 + invoice curl -s https://satsapi.dev/v1/price # → { "invoice": "lnbc30n1p...", "payment_hash": "fa7f01...", "amount_sats": 3 } # Step 2 — pay the invoice with any Lightning wallet # (Phoenix, Alby, Breez, lncli…) # Step 3 — retry with payment_hash as query param curl -s "https://satsapi.dev/v1/price?payment_hash=fa7f01..." | jq .
Error Codes
| Status | Code | Description |
|---|---|---|
| 402 | payment_required | Response body contains invoice and payment_hash. Pay the invoice, then retry with ?payment_hash=. |
| 429 | rate_limit_exceeded | Too many requests. Check Retry-After header. |
| 500 | upstream_error | External data source temporarily unavailable. |
| 503 | service_unavailable | API temporarily offline. |
Rate Limits
Rate limits are enforced per IP address:
| Tier | Endpoints | Limit |
|---|---|---|
| Standard | /v1/price · /v1/mempool · /v1/tx · /v1/onchain · /v1/derivatives | 60 req/min |
| AI | /v1/news · /v1/signal | 10 req/min |
| Heavy | /v1/summary | 5 req/min |
Authentication L402
SatsAPI uses the L402 protocol (HTTP 402 Payment Required) for authentication. Instead of API keys, you pay a tiny Lightning Network invoice per request. The payment hash becomes your proof of payment — no sessions, no cookies, no tokens to store.
L402 is designed for machine-to-machine micropayments — AI agents can pay for API calls autonomously without human intervention.
payment_hash is the proof.
Payment Flow
?payment_hash= query parameter — not as an Authorization header. This makes integration trivial from any HTTP client without special libraries.
Make the initial request
Call any endpoint as a standard GET request. No headers required.
Receive HTTP 402 + invoice
The server responds with status 402. The JSON body contains invoice (BOLT11), payment_hash and amount_sats.
Pay the Lightning invoice
Use any Lightning wallet — Phoenix, Alby, Breez, lncli — or any library. Payment settles in milliseconds.
Retry with ?payment_hash=
Resend the same request with the payment_hash from step 2 appended as a query parameter. The server verifies payment on phoenixd and returns the data.
402 Response Body
{
"error": "Payment Required",
"amount_sats": 3,
"invoice": "lnbc30n1p5xyzabc...",
"payment_hash": "fa7f01e2d3c4b5a6...",
"message": "Pay 3 sats to access this endpoint. Then retry with ?payment_hash=fa7f01..."
}
Authenticated Retry
# After paying the invoice, retry with the payment_hash curl "https://satsapi.dev/v1/price?payment_hash=fa7f01e2d3c4b5a6..." # Response: 200 OK with full data
Compatible Tools
| Tool | Type | Use case |
|---|---|---|
| Phoenix Wallet | Mobile | Pay invoices manually on iOS/Android. Copy the invoice from the 402 response body. |
| Alby | Browser ext. | Browser-based Lightning wallet. Supports WebLN for programmatic payments from frontend. |
| lncli | CLI | LND command-line client. lncli payinvoice <bolt11> |
| lnget | CLI | Drop-in L402 curl replacement. Handles 402 → pay → retry automatically. |
| WebLN | JS library | Browser-based Lightning API. await webln.sendPayment(invoice) |
| LNC | JS library | Lightning Node Connect. Node.js / browser library for server-side programmatic payments. |
Endpoint Reference
GET /v1/demo
Free demo endpoint returning real BTC price data — no Lightning wallet required. Limited to 5 calls per hour per IP. Designed for developers who want to try the API before setting up a Lightning payment.
Try it now
curl https://satsapi.dev/v1/demo
Example response
"endpoint": "/v1/demo", "cost_sats": 0, "demo": true, "data": { "price_usd": 69259, "change_24h_pct": 3.13, "volume_24h_usd": 49921543297, "market_cap_usd": 1384996162769, "timestamp": "2026-03-09T14:52:39.810Z" }, "upgrade": { "message": "Get RSI, MACD, signals, mempool, on-chain data and more — pay per call in sats.", "docs": "https://satsapi.dev/docs" }
Rate limit: 5 requests/hour per IP. No payment required. Real data from CoinGecko.
GET /v1/price
Returns the current BTC/USD price with key technical indicators: RSI-14, 50-day and 200-day moving averages, MACD bias, 24h change, high/low, volume and trend classification. Data sourced from CryptoCompare.
Response Fields
| Field | Type | Description |
|---|---|---|
| symbol | string | Always "BTC/USD" |
| price | number | Current price in USD |
| change_24h | string | 24h price change as percentage string (e.g. "-1.24%") |
| high_24h | number | 24h high price in USD |
| low_24h | number | 24h low price in USD |
| volume_24h | string | 24h trading volume (formatted, e.g. "$13.5B") |
| ma_50 | number | 50-day simple moving average |
| ma_200 | number | 200-day simple moving average |
| rsi_14 | number | 14-period RSI (0–100) |
| trend | string | "BULLISH" | "BEARISH" | "NEUTRAL" |
| macd_bias | string | "BULLISH" | "BEARISH" | "NEUTRAL" |
Example Response
{
"endpoint": "/v1/price",
"cost_sats": 3,
"data": {
"symbol": "BTC/USD",
"price": 84231.50,
"change_24h": "-1.24%",
"high_24h": 85900.00,
"low_24h": 83100.00,
"volume_24h": "$42.1B",
"ma_50": 87420.15,
"ma_200": 71380.44,
"rsi_14": 44.2,
"trend": "BEARISH",
"macd_bias": "BEARISH"
},
"timestamp": "2026-03-07T20:00:00.000Z"
}
GET /v1/mempool
Returns current mempool state: pending transaction count, congestion level, recommended fees for different confirmation targets, and last block data. Sourced from mempool.space.
Response Fields
| Field | Type | Description |
|---|---|---|
| pending_txs | number | Number of unconfirmed transactions |
| congestion | string | "LOW" | "MEDIUM" | "HIGH" |
| fees.fast_10min | string | Recommended fee for ~10 min confirmation |
| fees.medium_30min | string | Recommended fee for ~30 min confirmation |
| fees.slow_1h | string | Recommended fee for ~1 hour confirmation |
| last_block.height | number | Height of the most recently mined block |
| last_block.tx_count | number | Transactions in the last block |
GET /v1/tx/:txid
Looks up a Bitcoin transaction by TXID. Returns confirmation status, block position, fee details, input/output counts and transferred value. Sourced from mempool.space.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| txid | string | 64-character hex transaction ID |
Response Fields
| Field | Type | Description |
|---|---|---|
| status | string | "CONFIRMED" | "PENDING" |
| confirmations | number | Number of confirmations. 0 if unconfirmed. |
| block_height | number|null | Block height where tx was included. null if pending. |
| fee_sats | number | Total fee in satoshis |
| fee_rate | string | Fee rate in sat/vByte |
| inputs | number | Number of inputs |
| outputs | number | Number of outputs |
| value_btc | string | Total output value in BTC |
GET /v1/onchain
Aggregated on-chain intelligence: Fear & Greed index, BTC market dominance, circulating supply, network hashrate and an AI-derived market phase. Sources: alternative.me (Fear & Greed), CoinGecko (dominance/supply).
Response Fields
| Field | Type | Description |
|---|---|---|
| fear_and_greed.value | number | Index value 0–100 |
| fear_and_greed.label | string | "Extreme Fear" | "Fear" | "Neutral" | "Greed" | "Extreme Greed" |
| fear_and_greed.trend | string | "IMPROVING" | "DETERIORATING" | "STABLE" |
| dominance.btc_dominance | string | BTC market cap dominance percentage |
| supply.circulating_btc | number | Current circulating supply |
| network.hashrate_eh | number | Hash rate in exahashes/second |
| market_phase.phase | string | Detected market phase classification |
GET /v1/derivatives
Perpetual futures market data: funding rate, open interest trend, long/short ratio and leverage risk assessment.
estimated: true and a data_note field explaining this. Do not use this endpoint for precise funding rate or open interest figures.
Response Fields
| Field | Type | Description |
|---|---|---|
| funding_rate.current_pct | number | Estimated 8-hour funding rate as percentage |
| funding_rate.bias | string | "BULLISH" | "NEUTRAL" | "BEARISH" | "SHORTS_PAYING" |
| open_interest.trend | string | "INCREASING" | "DECREASING" | "STABLE" |
| long_short.long_pct | number | Estimated percentage of accounts with long positions |
| leverage_risk | string | "LOW" | "MEDIUM" | "HIGH" | "EXTREME" |
| estimated | boolean | Always true — data is estimated from momentum |
| data_note | string | Explanation of estimation methodology |
GET /v1/news
AI-generated news sentiment analysis powered by Claude. Fetches the latest Bitcoin headlines from the CoinDesk RSS feed, analyzes them for market sentiment, and returns a structured summary with sentiment score, top 3 key events, and market impact narrative.
cached field indicates whether the response is fresh or served from cache. The cached_at timestamp tells you when the cache was last refreshed.
Response Fields
| Field | Type | Description |
|---|---|---|
| sentiment | string | "BULLISH" | "NEUTRAL" | "BEARISH" |
| score | number | Sentiment score 0.0–1.0 |
| summary | string | AI-generated 2-3 sentence market narrative |
| top_events | string[] | Array of 3 key news events |
| cached | boolean | true if response served from 6h cache |
| cached_at | string | ISO timestamp of last cache refresh |
GET /v1/signal
Multi-factor AI trading signal. Aggregates price, mempool, on-chain and derivatives data and sends it to Claude for analysis. Returns a BUY / SELL / HOLD signal with confluence score, detailed reasoning and an ATR-based trade setup when applicable.
Response Fields
| Field | Type | Description |
|---|---|---|
| signal | string | "BUY" | "SELL" | "HOLD" |
| confluence | number | Percentage of factors aligned (0–100) |
| confidence | number | Model confidence 0.0–1.0 |
| risk_level | string | "LOW" | "MEDIUM" | "HIGH" | "EXTREME" |
| reasoning | string | Analyst-grade explanation of the signal |
| trade_setup | object|null | Entry, stop-loss and target levels. null if no clear setup. |
| technicals.rsi_1d | number | Daily RSI |
| technicals.rsi_4h | number | 4-hour RSI |
| technicals.atr_14d | number | 14-day Average True Range in USD |
GET /v1/summary ★
The flagship endpoint. Aggregates all 7 other endpoints into a single comprehensive market intelligence report. Includes a 0–100 market score, AI executive summary, full risk matrix, key support/resistance levels and a flat bot_ready object designed for autonomous agent consumption.
Response Fields
| Field | Type | Description |
|---|---|---|
| market_score | number | Overall market score 0–100. <40 bearish · 40–60 neutral · >60 bullish. |
| market_score_label | string | "BEARISH" | "NEUTRAL" | "BULLISH" |
| executive_summary | string | 4-6 sentence analyst-grade narrative of current conditions. |
| bot_ready | object | Flat typed object with all critical fields. See below. Only available in /v1/summary. |
| risk_matrix | object[] | Array of risk/opportunity items with level and note. |
bot_ready Object
bot_ready object is exclusive to /v1/summary. It is not returned by /v1/signal. It provides a single flat object with all critical fields as primitives — no nested parsing required.
signal: "BUY" | "SELL" | "HOLD" confluence: number // 0–100 factor alignment market_score: number // 0–100 overall score price_usd: number // current BTC price rsi_1d: number // daily RSI rsi_4h: number // 4-hour RSI fear_greed: number // 0–100 index value fear_greed_label: string // human-readable classification funding_bias: "BULLISH" | "NEUTRAL" | "BEARISH" long_pct: number // % accounts long (estimated) leverage_risk: "LOW" | "MEDIUM" | "HIGH" | "EXTREME" support: number // key support level USD resistance: number // key resistance level USD highest_risk: string // top risk/opportunity label
Code Examples
JavaScript / Node.js
Full L402 payment flow
async function callSatsAPI(path) { // 1. Initial request let res = await fetch(`https://satsapi.dev${path}`); // 2. Handle 402 — pay Lightning invoice if (res.status === 402) { const body = await res.json(); // { invoice: "lnbc30n1...", payment_hash: "fa7f01...", amount_sats: 3 } // Pay with your Lightning wallet/library await wallet.payInvoice(body.invoice); // 3. Retry with payment_hash as query param res = await fetch( `https://satsapi.dev${path}?payment_hash=${body.payment_hash}` ); } return res.json(); } // Usage const { data } = await callSatsAPI('/v1/price'); console.log(data.price); // 84231.50 console.log(data.rsi_14); // 44.2 console.log(data.trend); // "BEARISH"
Get summary + bot_ready
const { data } = await callSatsAPI('/v1/summary'); const b = data.bot_ready; console.log(b.signal); // "HOLD" console.log(b.confluence); // 52 console.log(b.price_usd); // 84231.50 console.log(b.fear_greed); // 28 console.log(b.leverage_risk); // "LOW"
Python
import requests def call_sats_api(path: str, wallet=None) -> dict: url = f"https://satsapi.dev{path}" # 1. Initial request r = requests.get(url) # 2. Handle 402 payment if r.status_code == 402 and wallet: body = r.json() invoice = body["invoice"] payment_hash = body["payment_hash"] # Pay invoice with any LN wallet/library wallet.pay(invoice) # 3. Retry with payment_hash as query param r = requests.get(url, params={"payment_hash": payment_hash}) r.raise_for_status() return r.json() # Usage data = call_sats_api("/v1/signal")["data"] print(data["signal"]) # "HOLD" print(data["confluence"]) # 52 print(data["reasoning"]) # "Neutral RSI at 49.3..."
cURL
# Step 1 — get invoice curl -s https://satsapi.dev/v1/price # → {"invoice":"lnbc30n1p...","payment_hash":"fa7f01...","amount_sats":3} # Step 2 — pay invoice with your wallet (Phoenix, lncli, Alby…) # Step 3 — retry with payment_hash curl -s "https://satsapi.dev/v1/price?payment_hash=fa7f01..." | jq .data # Full summary curl -s "https://satsapi.dev/v1/summary?payment_hash=..." | jq .data.bot_ready # Transaction lookup curl -s "https://satsapi.dev/v1/tx/4a5e1e4baab89f3a...?payment_hash=..." | jq . # Using lnget (handles 402 automatically) lnget https://satsapi.dev/v1/signal | jq .data.signal
AI Agent Integration
SatsAPI is designed from the ground up for autonomous AI agents. The L402 protocol lets agents pay for data without human intervention, and the bot_ready object in /v1/summary eliminates all parsing complexity.
The bot_ready Object
Every call to /v1/summary returns a flat bot_ready object. All fields are primitives — no nested objects, no arrays, no post-processing required.
if (b.signal === 'BUY' && b.confluence > 65 && b.leverage_risk !== 'EXTREME') — that's the entire decision logic for a trading bot.
Autonomous Payment Flow
The full 402 → pay → retry cycle can be automated in ~10 lines. Using lnget, it's a single command:
# lnget handles 402 → pay → retry automatically
lnget https://satsapi.dev/v1/summary | jq .data.bot_ready
Integration Examples
LangChain Tool
import { Tool } from "langchain/tools"; class BitcoinIntelligenceTool extends Tool { name = "bitcoin_market_intelligence"; description = "Returns BTC market signal (BUY/SELL/HOLD), " + "price, RSI, risk and confluence score. " + "Call before any Bitcoin-related decision."; async _call() { // Step 1 — get invoice let res = await fetch("https://satsapi.dev/v1/summary"); if (res.status === 402) { const { invoice, payment_hash } = await res.json(); await this.wallet.payInvoice(invoice); // pay 200 sats res = await fetch( `https://satsapi.dev/v1/summary?payment_hash=${payment_hash}` ); } const { data } = await res.json(); return JSON.stringify(data.bot_ready); } } // Agent receives a flat object — no parsing needed: // { signal:"HOLD", confluence:52, price_usd:84231, fear_greed:28, // support:79400, resistance:91200, leverage_risk:"LOW" }
Cron-based trading bot
// Runs every 4 hours — costs 200 sats/run (~1,200 sats/day) async function tradingCycle() { // Fetch + pay in one helper const { data } = await callSatsAPI("/v1/summary"); const b = data.bot_ready; // Only act on high-confluence signals if (b.signal === "BUY" && b.confluence >= 65 && b.leverage_risk !== "EXTREME") { await exchange.createOrder("BTC/USDT", "buy", b.price_usd * 0.995); log(`BUY @ ${b.price_usd} — confluence ${b.confluence}% — stop ${b.support}`); } if (b.signal === "SELL" && b.confluence >= 70) { await exchange.closePositions(); log(`SELL @ ${b.price_usd} — market score ${b.market_score}/100`); } } cron.schedule("0 */4 * * *", tradingCycle);
AutoGPT / OpenAgents function definition
tools = [{
"type": "function",
"function": {
"name": "get_bitcoin_signal",
"description": "Get current BTC market signal and risk. Returns bot_ready object.",
"parameters": { "type": "object", "properties": {} }
}
}]
def get_bitcoin_signal():
# Step 1 — request
r = requests.get("https://satsapi.dev/v1/summary")
if r.status_code == 402:
body = r.json()
wallet.pay(body["invoice"])
r = requests.get(
"https://satsapi.dev/v1/summary",
params={"payment_hash": body["payment_hash"]}
)
return r.json()["data"]["bot_ready"]