Browse API groups
API Documentation
Getting started
The base URL is https://quantascan.io/api/v1. Every request needs a personal API key: send it as an Authorization: Bearer qs_... header (create one from your account page; sign-up is free). Every response is JSON.
# Create a free account, generate a personal API key, then:
curl -s -H "Authorization: Bearer qs_your_key_here" \
"https://quantascan.io/api/v1/qrl2/blocks/latest"Running the stack locally? The same paths are served on http://localhost:3000/api/v1 (frontend proxy) or directly on the backend at http://localhost:8000/api/v1.
Endpoint reference
Block listings, lookups by height or hash, and block-level statistics for both chains.
Transaction listings, lookups, whale transfers, revert reasons and the QRL 2.0 pending-transaction pool.
Address summaries, balances, transaction history and counterparty analysis.
The display name for an address: a curated Quantascan label when one exists, otherwise a unique auto-generated nickname. Nicknames are a pure function of the address — the algorithm, word lists and golden vectors are published at /nicknames/v1/ so you can compute virtually every name offline and use these endpoints only for curated labels and the small collision-arbitration list.
Wallet-level aggregates: portfolio views, activity and holdings over time.
QRC-20/721/1155 token metadata, holders, distribution and decoded transfer events (QRL 2.0 EVM).
NFT collections, items and ownership on QRL 2.0.
Smart-contract metadata, source verification and read-only contract calls (QRL 2.0 EVM).
Validator registry, performance and EIP-4895 withdrawals on the QRL 2.0 proof-of-stake chain.
Consensus-layer data: beacon blocks, slots, epochs and slashings (QRL 2.0).
Proof-of-Work mining on the QRL legacy chain: block-reward emission, difficulty, hashrate, and the top miners and pools.
On-chain messages anchored with the QRL legacy message transaction subtype: a browsable feed with text/binary payloads, plus headline stats.
Network-wide time-series and aggregates: activity, supply, fees, gas, whales and cross-chain timelines.
Market price data and the cross-chain richlist of largest holders.
External attention signals over time: Google Trends relative search interest and Reddit discussion volume for QRL and quantum-computing topics. Chain-agnostic; relative, not absolute.
Standard JSON-RPC 2.0 for wallets and exchanges: read chain state, estimate gas, get receipts and broadcast signed transactions (qrl_sendRawTransaction) without running your own QRL 2.0 node. Whitelisted qrl_* methods only; batches of up to 20 requests, each counted as one call; API key required.
The module/action query API most block-explorer client libraries already speak (GET /api?module=account&action=txlist&address=…&apikey=qs_…), for QRL 2.0. Point existing client code at https://quantascan.io/api by changing the base URL. Addresses are Q-prefixed (0x is accepted on input); errors keep the same {status, message, result} body but use real HTTP status codes.
Your API key's own plan and quota: today's calls, the daily limit shared across all keys of your account or organisation, the per-key burst, when the quota resets, and the last 30 days. The same numbers ride on every response as X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-Reset and X-API-Plan.
Authentication
- An API key is required. Every endpoint in this reference takes an
Authorization: Bearer qs_...header with a personal API key, created from your account page after signing in. A free account is all you need: the same key works across every documented endpoint. - Managing keys and account data (creating or revoking keys, webhooks, watchlists, alerts) happens in the signed-in account UI, not through this public API. Those endpoints require an active browser session and are intentionally left out of this reference.
- Label submissions are moderated: community labels enter a review queue and are IP-rate-limited to 5 submissions per hour.
Rate limits
Limits depend on your plan: a daily quota shared across all your keys (resets at 00:00 UTC) plus a burst limit per minute for each key. The current numbers are on the free API page. Exceeding a limit returns 429 with a Retry-After header, so clients can pace themselves.
- Responses carry
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-ResetandX-API-Planheaders. GET /api/v1/usagereturns your plan, calls used today, calls remaining and the reset time.- For sustained high-volume use, cache on your side: most aggregates only change once per day.
Attribution
The free API is free for personal and commercial use. In return, show a visible “Powered by Quantascan” text or badge linking to https://quantascan.io on every page or screen that shows the data: in apps and command-line tools, in the about or credits screen and in your documentation.
<a href="https://quantascan.io" rel="noopener"><img src="https://quantascan.io/badges/powered-by-quantascan.svg" alt="Powered by Quantascan" width="180" height="40"></a>[](https://quantascan.io)Data: Quantascan (https://quantascan.io)For apps, command-line tools and docs: put this in your about or credits screen and in your README.
Conventions
- Chain selector: chain-specific endpoints live under
/api/v1/qrl2/...(QRL 2.0, PoS EVM) or/api/v1/qrl/...(QRL legacy, PoW). Cross-chain endpoints (analytics, search, price) live at/api/v1/...with no chain segment; a few of them take?chain=qrl|qrl2as an optional query param. QRL2-only resources (validators, beacon, withdrawals, mempool, contracts, fees, nft, token-transfers) live only under/api/v1/qrl2/.... - Pagination:
?page=1&page_size=25for offset, or?cursor=...for cursor (deeper, O(log N)). Cursors come back asnext_cursor. - Big numbers (value, fee, supply) are returned as decimal strings to preserve UInt256 precision. Parse with
BigInt(...)in JavaScript. - Error envelope: every 4xx/5xx returns
{"error": {"code", "message", "request_id"}}. Quote therequest_idwhen reporting bugs.
Webhooks
Get a signed POST to your server when a watched address or token contract has on-chain activity: deposit detection without polling. Create endpoints in your account; the signing secret (whsec_…) is shown once. The Free plan includes 2 endpoints and 25 watched addresses (addresses and token contracts, across all endpoints).
Events
address_activity: native transfers to or from a watched address (QRL and QRL 2.0).token_transfer: token transfers involving a watched address and/or a watched token contract (QRL 2.0).internal_transfer: value moved by a contract call to or from a watched address (QRL 2.0).withdrawal: validator withdrawals to a watched address (QRL 2.0).- An optional minimum value (base units: shor on QRL, planck on QRL 2.0) filters out small native transfers. Every delivery carries
valuein base units andvalue_displayin QRL / Quanta.
Payload
{
"id": "qrl2:0x8f2c…e41a:0:address_activity",
"type": "address_activity",
"api_version": "2026-10-22",
"chain": "qrl2",
"network": "mainnet",
"block_height": 1284512,
"block_hash": "0x5b7d…09c3",
"timestamp": "2026-10-22T12:00:00Z",
"tx_hash": "0x8f2c…e41a",
"from": "Q20b7…a1f4",
"to": "Q9c0e…77d2",
"value": "2500000000000000000000",
"value_display": "2500",
"unit": "Quanta",
"token_contract": null,
"matched_addresses": ["Q9c0e…77d2"],
"confirmations_at_send": 3,
"finalized": false,
"data": {},
"created_at": "2026-10-22T12:00:40Z"
}Verifying the signature
Each request carries X-Quantascan-Signature: t=<unix>,v1=<hex>, where v1 is the HMAC-SHA256 of <t>.<raw body> keyed with your secret. Also sent: X-Quantascan-Event, X-Quantascan-Delivery, X-Quantascan-Timestamp and X-Quantascan-Attempt. Reject timestamps older than 5 minutes. For 24 hours after a secret rotation the header carries two v1 values (new secret first): accept the request when any of them matches.
Node.js
import crypto from "node:crypto";
import express from "express";
const app = express();
const SECRET = process.env.QUANTASCAN_WEBHOOK_SECRET; // whsec_…
// Verify the RAW body bytes — never a re-serialised object.
app.post("/quantascan/webhook", express.raw({ type: "application/json" }), (req, res) => {
const parts = (req.get("X-Quantascan-Signature") ?? "").split(",");
const t = parts.find((p) => p.startsWith("t="))?.slice(2);
const sigs = parts.filter((p) => p.startsWith("v1=")).map((p) => p.slice(3));
if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return res.sendStatus(400);
const expected = crypto
.createHmac("sha256", SECRET)
.update(`${t}.`)
.update(req.body)
.digest("hex");
const ok = sigs.some(
(s) => s.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected)),
);
if (!ok) return res.sendStatus(401);
// At-least-once delivery: skip a delivery you already processed.
const deliveryId = req.get("X-Quantascan-Delivery");
// if (await alreadyProcessed(deliveryId)) return res.sendStatus(200);
const event = JSON.parse(req.body.toString("utf8"));
// event.type: address_activity | token_transfer | internal_transfer | withdrawal | reorg | test
res.sendStatus(200); // any 2xx = delivered
});Python
import hashlib, hmac, os, time
from flask import Flask, abort, request
app = Flask(__name__)
SECRET = os.environ["QUANTASCAN_WEBHOOK_SECRET"].encode() # whsec_…
def verify(header: str, body: bytes, tolerance: int = 300) -> bool:
parts = [p.split("=", 1) for p in header.split(",") if "=" in p]
ts = next((v for k, v in parts if k == "t"), "")
sigs = [v for k, v in parts if k == "v1"]
if not ts.isdigit() or abs(time.time() - int(ts)) > tolerance:
return False
expected = hmac.new(SECRET, ts.encode() + b"." + body, hashlib.sha256).hexdigest()
return any(hmac.compare_digest(expected, s) for s in sigs)
@app.post("/quantascan/webhook")
def webhook():
# request.get_data() = the raw body bytes the signature covers.
if not verify(request.headers.get("X-Quantascan-Signature", ""), request.get_data()):
abort(401)
delivery_id = request.headers["X-Quantascan-Delivery"] # dedupe on this
event = request.get_json()
return "", 200Delivery, retries and reorgs
- At least once. The same event can arrive more than once: dedupe on
X-Quantascan-Delivery(equal to the payloadid). - After confirmations: events are sent once the block has 6 confirmations on QRL and 3 on QRL 2.0.
- Retries: any non-2xx answer or a timeout (10 s) is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 12 h; after 8 failed attempts the delivery is dead. A
Retry-Afterheader is honoured up to 12 h. Redirects are not followed. - Auto-disable: an endpoint that keeps failing (50 failures in a row over more than 24 hours) is disabled and you get a notification; re-enable it in your account. You can resend any delivery from the deliveries table.
- Reorgs:if a delivered event's block is replaced, you receive a
reorgevent with id<original id>:reorg. A transaction re-included in a new block is delivered again under a new id.
Explorer-compatible API
A drop-in endpoint for the ?module=…&action=… query format most block-explorer client libraries already speak: point existing client code at the base URL https://quantascan.io/api and pass your key as the apikey query parameter.
curl -s "https://quantascan.io/api?module=account&action=txlist\
&address=Q20b7a1f4…&page=1&offset=25&sort=desc&apikey=qs_your_key_here"{
"status": "1",
"message": "OK",
"result": [ … ]
}- Modules:
account,contract,transaction,block,logs,stats,gastracker,proxy(node-style action names are translated to theqrl_*methods) andgetapilimit. - QRL 2.0 only. The original QRL chain is served by the REST API.
- Addresses come back Q-prefixed;
0x-prefixed addresses are accepted on input. - Errors use real HTTP status codes (400, 401, 404, 429, …) with the same
{status, message, result}body, so clients can tell a failure from an empty result. - Contract verification:
module=contract&action=verifysourcecode(POST) queues a Hyperion source verification and returns a guid;action=checkverifystatuspolls it. Full walkthrough in the contract verification guide. - Calls count against your plan's daily quota like any other API call.
JSON-RPC endpoint
POST https://quantascan.io/api/v1/qrl2/rpc speaks standard JSON-RPC 2.0 for QRL 2.0, so wallets and RPC libraries can use it like a node. Authenticate with Authorization: Bearer qs_….
curl -s https://quantascan.io/api/v1/qrl2/rpc \
-H "Authorization: Bearer qs_your_key_here" \
-H "Content-Type: application/json" \
-d '[{"jsonrpc":"2.0","id":1,"method":"qrl_blockNumber","params":[]},
{"jsonrpc":"2.0","id":2,"method":"qrl_getBalance","params":["Q20b7a1f4…","latest"]}]'- Whitelisted methods: the
qrl_*read methods (block number, chain id, sync state, gas price and fee history, balance, nonce, code, storage,qrl_call,qrl_estimateGas, blocks, headers, receipts, transactions andqrl_getLogs) plusnet_version,web3_clientVersionandqrl_sendRawTransaction. Anything else (includingeth_*names) returns error-32601. - Batches of up to 20 requests; each item counts as one call against your quota.
qrl_getLogsneeds an address or topic filter and a bounded block range.qrl_sendRawTransactionhas its own limit of 10 calls per minute per key, on top of your plan limits.
CSV export
GET /api/v1/{chain}/addresses/{address}/export.csv?from=YYYY-MM-DD&to=YYYY-MM-DD&type=… streams one address's history as CSV for tax and accounting tools. The same export is on every address page (“Export CSV”).
curl -sLOJ -H "Authorization: Bearer qs_your_key_here" \
"https://quantascan.io/api/v1/qrl/addresses/Q0105…/export.csv?from=2025-01-01&to=2025-12-31&type=transactions"type:transactions(default),internal,tokensorwithdrawals(QRL 2.0 only).- Columns: date (UTC), block, transaction hash, direction, from, to, value (QRL or Quanta), fee (paid by this address, once per transaction), token, type, status and, where we have a daily price, USD price and value.
- At most 366 days and 100,000 rows per file. A larger range returns
422(range_too_longortoo_many_rows) instead of a truncated file. Export one year, or a shorter range, at a time. - With an API key it counts as one call; without one (the website) it is limited to 10 exports per hour per IP address.
Machine-readable spec
The reference on this site is generated from the OpenAPI 3.1 spec. Download it to generate a typed client, import the API into Postman, or hand it to an AI coding tool:
FAQ about the API
Common questions about this page
- Is the Quantascan API free to use?
- Yes. It does require a free account and a personal API key: every request is authenticated with an Authorization: Bearer qs_... header, and is rate-limited to keep the service fair. The free plan covers personal and commercial use, as long as you show a visible "Powered by Quantascan" link wherever the data appears. See the attribution kit. Need higher limits? Contact us.
- What are the rate limits?
- Limits depend on your plan: a daily quota shared across all your keys (resets 00:00 UTC) plus a burst limit per minute for each key. See the free API page for the current numbers. Exceeding a limit returns HTTP 429 with a Retry-After header. Responses carry X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset and X-API-Plan headers, and GET /api/v1/usage returns your plan, usage today and remaining calls.
- How do I query QRL (PoW) vs QRL 2.0 data?
- Chain-specific endpoints carry the chain in the path: /api/v1/qrl2/... for QRL 2.0 (proof-of-stake, EVM) and /api/v1/qrl/... for the original QRL chain (proof-of-work). Cross-chain endpoints such as analytics, search and the richlist live at /api/v1/... without a chain segment; some accept an optional ?chain= query parameter.
- How do I get historical time-series data?
- The Analytics group exposes daily time-series (transactions, supply, fees, active addresses and more) going back to the genesis of each chain. Most accept a ?days= parameter; cross-chain timelines stitch the original Proof-of-Work chain and QRL 2.0 into one continuous series.
- Is there a WebSocket API?
- Yes, /api/v1/ws/live pushes new-block events per chain. It is a notification stream: subscribe for wake-ups, then fetch details over REST. The WebSocket endpoint is not part of the OpenAPI spec.
- Are amounts returned as numbers?
- Large amounts (values, fees, supply) are returned as decimal strings to preserve full integer precision beyond JavaScript's Number.MAX_SAFE_INTEGER. Parse them with BigInt(...) in JavaScript or int(...) in Python.