API Reference
Getting Started
Base URL: https://microquery.dev · All amounts in micro-USDC (1 USDC = 1,000,000 micro-USDC).
# 1. Register — get an API key and $0.10 free trial credit curl -X POST https://microquery.dev/v1/register \ -H "Content-Type: application/json" \ -d '{"name": "my-agent"}' # → { "id": "...", "api_key": "a3f1b2c9...", "balance": 100000 } # 2. Query curl -G https://microquery.dev/query \ -H "Authorization: Bearer YOUR_API_KEY" \ --data-urlencode "database=nvd" \ --data-urlencode "query=SELECT id, description FROM cve WHERE cvss_score > 9 LIMIT 5" # → ndjson rows + X-Microquery-Cost-MicroUSDC and X-Microquery-Balance-MicroUSDC headers
No wallet required. The trial credit covers thousands of small queries. When the trial runs out, add a wallet and deposit USDC.
Registration
POST /v1/register — public, no authentication required.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | yes | Display name, max 64 characters |
| wallet_addr | string | no | Ethereum wallet address. Optional at registration — enables account recovery and deposits. See Deposits. |
// Response 201 Created { "id": "acct_...", "api_key": "abc123...", // shown once — store securely "name": "my-agent", "balance": 100000, // free trial credit in micro-USDC "wallet_addr": "0x...", "first_query": { "database": "nvd", "sql": "SELECT id, description FROM cve WHERE cvss_score > 9 LIMIT 3", "note": "Trial balance covers all example scripts" }, "deposit_instructions": { "chain": "Base", "token": "USDC", "minimum_micro_usdc": 250000, "endpoint": "POST /v1/deposit", "method": "EIP-2612 permit: sign permit off-chain, send amount+deadline+v+r+s with Bearer auth", "docs_url": "https://microquery.dev/docs.md#deposits" }, "quickstart_url": "https://microquery.dev/v1/agent-quickstart" }
first_query and deposit_instructions so an autonomous agent can proceed without any further human instruction.
Agent bootstrap endpoint
GET /v1/agent-quickstart — public, no authentication required.
Returns a self-contained JSON document designed to be injected directly into an agent's context. The response describes every step needed for an autonomous agent to register, run its first query, and deposit funds — without consulting external documentation.
curl https://microquery.dev/v1/agent-quickstartThe response includes service, registration, authentication, query, first_query, pricing, deposit, datasets, and a discovery section documenting GET /v1/databases. This endpoint is the canonical MCP tool manifest entry point.
Authentication
Bearer token (API key)
Authorization: Bearer YOUR_API_KEY
EIP-712 signed authorization (advanced — per-query spending caps)
For agents that want a cryptographic per-query spending cap. Each request carries a signed authorization binding the query to a maximum cost — the server rejects if the actual scan would exceed max_cost. Requires a linked wallet. Most agents do not need this; the deposit balance is the effective spending cap.
Authorization: EIP712 BASE64_ENCODED_PAYLOAD // Payload (base64-encoded JSON) { "consumer": "0xYOUR_WALLET", "max_cost": "5000", // hard cap in micro-USDC "database": "nvd", "query_hash": "0x...", // SHA-256 of the query string "nonce": 1, "deadline": 1234567890, // unix timestamp "signature": "0x..." }
Querying
GET /query or POST /query
| Parameter | Description |
|---|---|
| database | Database name (e.g., nvd, pubmed, sec) |
| query | SQL query string |
Response is newline-delimited JSON (application/x-ndjson), one object per row.
For agents without a pre-funded account that want to pay per query without registration, see Advanced: x402.
Response headers
| Header | Description |
|---|---|
| X-Microquery-Cost-MicroUSDC | Actual cost of this query in micro-USDC |
| X-Microquery-Balance-MicroUSDC | Remaining balance after this query in micro-USDC |
| X-Microquery-Bytes-Scanned | Decompressed bytes scanned |
| X-Microquery-Query-ID | Opaque query identifier |
| X-Microquery-Auto-Limit | Set to 1000 when a LIMIT clause was automatically injected — add an explicit LIMIT to your query to suppress this and retrieve more rows (up to 10,000) |
| X-Microquery-Hard-Limit | Set to 10000 when your explicit LIMIT exceeded the server maximum and was clamped |
| X-Payment-Transaction | On-chain settlement tx hash (x402 per-query only) |
| X-Payment-Account-Key | api_key for this wallet — returned on first x402 per-query payment only |
Status codes
| Code | Meaning |
|---|---|
| 200 | Query executed; results follow |
| 402 | Either insufficient balance ({"error":"insufficient balance",...}) or an x402 challenge ({"x402Version":1,"accepts":[…]}) — sign for maxAmountRequired and retry with X-PAYMENT |
| 401 | Missing authorization |
| 403 | Invalid token or EIP-712 signature |
Pricing
150 micro-USDC per GiB decompressed bytes scanned — approximately $0.15 / TB.
- Trial credit: 100,000 micro-USDC ($0.10) on every new account (no deposit needed)
- Minimum deposit: 250,000 micro-USDC (0.25 USDC)
# Current rate GET /v1/pricing // Response { "micro_usdc_per_gib": 150 }
Cost estimation
GET /v1/estimate or POST /v1/estimate — authenticated, free (no charge deducted). Returns the estimated maximum bytes and cost for a query without executing it.
curl -G https://microquery.dev/v1/estimate \
-H "Authorization: Bearer YOUR_API_KEY" \
--data-urlencode "database=pubmed" \
--data-urlencode "query=SELECT * FROM baseline WHERE MedlineCitation.Article.ArticleTitle ~ 'CRISPR'"
// Response:
{ "database": "pubmed", "estimated_bytes_scanned": 53687091200, "estimated_cost_micro_usdc": 7500 }
estimated_bytes_scanned is a conservative upper bound — actual scan size at execution time will be equal or lower.
Databases
GET /v1/databases — public, no authentication required.
Returns an object with a databases array and a _hint field. Each table entry includes fields and a partitioning summary (key, type, total_bytes).
| Parameter | Description |
|---|---|
partitions=true | Include per-partition byte breakdown for each table. Response grows to ~500 KB uncompressed; use only when reasoning about specific date or year coverage. |
// GET /v1/databases { "databases": [ { "name": "pubmed", "tables": [ { "name": "baseline", "fields": ["MedlineCitation.PMID", "..."], "partitioning": { "key": "pub_year", "type": "int", "total_bytes": 137737797632, "updated_at": "2026-04-15T18:17:35Z" } } ] } ], "_hint": "Add ?partitions=true to include per-partition byte breakdown for each table." }
With ?partitions=true each partitioning object also includes a partitions array of {"value": "...", "bytes": N} entries sorted by partition value.
| Database | Tables | Total size |
|---|---|---|
nvd | cve | ~0.7 GB |
osv | advisories | ~0.4 GB |
sec | edgar | ~6 GB |
clinicaltrials | studies | ~0.7 GB |
fda | faers | ~6.5 GB |
pubmed | baseline | ~138 GB |
btc | blocks, outputs | ~121 GB |
eth | blocks, contracts, dex_swaps, lending, lp_events, transactions, transfers | ~234 GB |
Deposits
You do not need a wallet to start. The $0.10 trial credit requires only POST /v1/register. A wallet is only needed when you want to top up.
Wallet setup
Generate a dedicated wallet for the agent in code, then send USDC to it from your personal wallet. Do not share your personal wallet’s private key with an agent.
import { ethers } from "ethers"; // Generate once, store the private key securely const wallet = ethers.Wallet.createRandom(); console.log("address: ", wallet.address); console.log("private_key: ", wallet.privateKey); // Load at startup const wallet = new ethers.Wallet(process.env.AGENT_PRIVATE_KEY);
Send USDC (on Base) to the agent address from Coinbase, MetaMask, Rabby, or any Base-compatible wallet. Minimum $0.25 USDC; $1–5 covers thousands of queries. To get USDC on Base: withdraw from Coinbase exchange directly to Base, bridge via bridge.base.org, or use any CEX that supports Base withdrawals.
In production, give each agent instance its own wallet — independent balances, per-agent spend visibility, and isolation if one is compromised.
Gasless permit deposit (EIP-2612)
Sign a USDC permit off-chain, send it to POST /v1/deposit with Bearer auth. The server submits depositWithPermit() on-chain using the operator key. Minimum: 250,000 micro-USDC ($0.25).
POST /v1/deposit Authorization: Bearer YOUR_API_KEY { "amount": 1000000, // micro-USDC (minimum 250000 = 0.25 USDC) "deadline": 1234567890, // Unix timestamp "v": 27, "r": "0x...", "s": "0x..." } // Response: { "tx_hash": "0x...", "amount": 1000000, "balance": 1005000, "transaction_id": "..." }
The account is credited once the transaction is mined (~2 s on Base).
Escrow: 0xb1f8eE89bc8E51558a3C2A216620aBa1b7B2d01A — Base USDC: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
For the full EIP-2612 permit signing example (Python), see docs.md §Deposits. To deposit without registering first, see Advanced: x402.
Advanced: x402
The x402 protocol is an alternative payment path for agents that are already crypto-native and prefer on-chain authorization without pre-registration. Most agents should use the Bearer + deposit path above.
x402 deposit — auto-register on first payment
An x402 deposit auto-creates an account on first use. No prior registration required. Sign an EIP-3009 transferWithAuthorization and POST to /v1/deposit with an X-PAYMENT header. No ETH needed.
POST /v1/deposit X-PAYMENT: <base64url-encoded x402 JSON> Content-Type: application/json {} // First deposit — 201 Created: { "api_key": "...", "balance_micro_usdc": 250000, "transaction": "0x...", "network": "base" } // Top-up — 200 OK: { "balance_micro_usdc": 1000000, "transaction": "0x...", "network": "base" }
Save the returned api_key — use it as a Bearer token for subsequent queries. For the full Python signing example, see docs.md §Advanced: x402.
x402 per-query — no registration, no pre-deposit
Each query is a self-contained payment. Send the query without an Authorization header; the server returns a 402 challenge with the exact cost. Sign an EIP-3009 transferWithAuthorization for that amount and retry with the X-PAYMENT header. Minimum: 10,000 micro-USDC ($0.01) per query.
Step 1 — get the cost:
# POST without auth — returns HTTP 402 with the challenge curl -s -X POST "https://microquery.dev/query?database=defi" \ -H "Content-Type: text/plain" \ --data "SELECT name, tvl FROM protocols ORDER BY tvl DESC LIMIT 5" // 402 response: { "x402Version": 1, "accepts": [{ "scheme": "exact", "network": "base", "maxAmountRequired": "10000", "payTo": "0x5da586b29c3bb0f86cf820b9ac4331b289a6e50b", "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "maxTimeoutSeconds": 60 }] }
Step 2 — sign EIP-3009 and retry (Python):
import base64, json, secrets, time from eth_account import Account from eth_account.messages import encode_typed_data amount = int(challenge["accepts"][0]["maxAmountRequired"]) pay_to = challenge["accepts"][0]["payTo"] usdc_addr = challenge["accepts"][0]["asset"] acct = Account.from_key(PRIVATE_KEY) nonce = "0x" + secrets.token_hex(32) signed = acct.sign_message(encode_typed_data(full_message={ "types": { "EIP712Domain": [ {"name": "name", "type": "string"}, {"name": "version", "type": "string"}, {"name": "chainId", "type": "uint256"}, {"name": "verifyingContract", "type": "address"}, ], "TransferWithAuthorization": [ {"name": "from", "type": "address"}, {"name": "to", "type": "address"}, {"name": "value", "type": "uint256"}, {"name": "validAfter", "type": "uint256"}, {"name": "validBefore", "type": "uint256"}, {"name": "nonce", "type": "bytes32"}, ], }, "domain": {"name": "USD Coin", "version": "2", "chainId": 8453, "verifyingContract": usdc_addr}, "primaryType": "TransferWithAuthorization", "message": { "from": acct.address, "to": pay_to, "value": amount, "validAfter": 0, "validBefore": int(time.time()) + 300, "nonce": nonce, }, })) payload = { "x402Version": 1, "scheme": "exact", "network": "base", "payload": { "signature": "0x" + signed.signature.hex(), "authorization": { "from": acct.address, "to": pay_to, "value": str(amount), "validAfter": "0", "validBefore": str(int(time.time()) + 300), "nonce": nonce, }, }, } x_payment = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip("=") import requests resp = requests.post( "https://microquery.dev/query?database=defi", headers={"Content-Type": "text/plain", "X-PAYMENT": x_payment}, data="SELECT name, tvl FROM protocols ORDER BY tvl DESC LIMIT 5", ) # resp.status_code == 200; NDJSON rows in resp.text # resp.headers["X-Payment-Transaction"] — on-chain tx hash # resp.headers.get("X-Payment-Account-Key") — api_key (first payment only)
On the first payment from a wallet the server auto-creates an account and returns the api_key in X-Payment-Account-Key. Save it to use the cheaper Bearer token path for subsequent queries. Any balance left over after the actual query cost carries forward.
Account Management
| Endpoint | Auth | Description |
|---|---|---|
| GET /v1/accounts/{id} | Bearer | Account details and balance |
| GET /v1/accounts/{id}/transactions | Bearer | Transaction history; supports limit and offset |
| POST /v1/wallet-challenge | Public | Issue a one-time nonce for wallet ownership verification (step 1 of link-wallet) |
| POST /v1/accounts/{id}/link-wallet | Bearer | Link a verified Ethereum wallet (step 2 — requires nonce + signature) |
| GET /v1/wallets/{addr} | Public | Recover account ID by wallet address (no API key returned) |
Linking a wallet
Ownership is verified via a challenge/response before the address is stored.
Step 1 — request a nonce:
POST /v1/wallet-challenge
{ "wallet_addr": "0xYOUR_WALLET" }
// Response:
{ "nonce": "a3f1c8...", "message": "microquery wallet verification\nnonce: a3f1c8...", "expires_in": 300 }
Step 2 — sign the message with eth_personalSign (MetaMask, signer.signMessage() in ethers.js, eth.sign() in web3.py), then submit:
POST /v1/accounts/{id}/link-wallet
{ "wallet_addr": "0xYOUR_WALLET", "nonce": "a3f1c8...", "signature": "0x..." }
The nonce expires after 5 minutes and is single-use.
GET /v1/wallets/{addr} to look up their account ID, then continue authenticating via EIP-712 signatures — no API key required.
Rate limits
| Endpoint | Limit |
|---|---|
| POST /v1/register | 3 accounts per IP per 24 hours |
| GET/POST /query | None — balance is the throttle |