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.

FieldTypeRequiredDescription
namestringyesDisplay name, max 64 characters
wallet_addrstringnoEthereum 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"
}
Every new account receives 100,000 micro-USDC ($0.10) free trial credit. The response includes 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-quickstart

The 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

ParameterDescription
databaseDatabase name (e.g., nvd, pubmed, sec)
querySQL 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

HeaderDescription
X-Microquery-Cost-MicroUSDCActual cost of this query in micro-USDC
X-Microquery-Balance-MicroUSDCRemaining balance after this query in micro-USDC
X-Microquery-Bytes-ScannedDecompressed bytes scanned
X-Microquery-Query-IDOpaque query identifier
X-Microquery-Auto-LimitSet 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-LimitSet to 10000 when your explicit LIMIT exceeded the server maximum and was clamped
X-Payment-TransactionOn-chain settlement tx hash (x402 per-query only)
X-Payment-Account-Keyapi_key for this wallet — returned on first x402 per-query payment only

Status codes

CodeMeaning
200Query executed; results follow
402Either insufficient balance ({"error":"insufficient balance",...}) or an x402 challenge ({"x402Version":1,"accepts":[…]}) — sign for maxAmountRequired and retry with X-PAYMENT
401Missing authorization
403Invalid 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).

ParameterDescription
partitions=trueInclude 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.

DatabaseTablesTotal size
nvdcve~0.7 GB
osvadvisories~0.4 GB
secedgar~6 GB
clinicaltrialsstudies~0.7 GB
fdafaers~6.5 GB
pubmedbaseline~138 GB
btcblocks, outputs~121 GB
ethblocks, 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.

At microquery’s typical query costs ($0.0001–$0.012), the x402 facilitator fee ($0.001/tx) represents significant overhead. This path is best suited for higher-value queries or agents already integrated with the x402 protocol.

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

EndpointAuthDescription
GET /v1/accounts/{id}BearerAccount details and balance
GET /v1/accounts/{id}/transactionsBearerTransaction history; supports limit and offset
POST /v1/wallet-challengePublicIssue a one-time nonce for wallet ownership verification (step 1 of link-wallet)
POST /v1/accounts/{id}/link-walletBearerLink a verified Ethereum wallet (step 2 — requires nonce + signature)
GET /v1/wallets/{addr}PublicRecover 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.

Account recovery: autonomous agents that lose their API key can call GET /v1/wallets/{addr} to look up their account ID, then continue authenticating via EIP-712 signatures — no API key required.

Rate limits

EndpointLimit
POST /v1/register3 accounts per IP per 24 hours
GET/POST /queryNone — balance is the throttle