Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

API Endpoints

The server exposes the following HTTP endpoints:

MethodPathPurpose
GET/Dashboard landing page (HTML), only mounted when dashboards: is configured
GET/{slug}/...Static files for an Evidence dashboard (one route per dashboards: entry)
GET/api/JSON discovery document — server info, endpoints, table summaries
GET/api/query?query=…Submit a SQL query (paywalled per the table’s price tags)
GET/api/table/{name}Full schema and pricing for a single table; optionally paywalled via MetadataPrice

All paid endpoints follow the x402 V2 protocol. The Payment-Signature header carries the base64-encoded PaymentPayload; the server replies with a Payment-Required header on 402 alongside a JSON body.


GET /

When dashboards are configured, the root path serves an HTML landing page listing every enabled dashboard with its title, description, and tags. The page is generated by tiders-x402-server dashboard … into <dashboards_root>/index.html and re-served verbatim. If dashboards_root/index.html is missing, the server returns 503 with a hint to run the dashboard subcommand.

When no dashboards are configured, / is unmounted and falls through to a 404 from the (empty) dashboard sub-router.


GET /api/

Returns a JSON discovery document — the canonical machine-readable description of the server.

Request

curl http://localhost:4021/api/

Response (200 OK, application/json)

{
  "server": {
    "url": "http://localhost:4021/",
    "version": "0.3.0",
    "facilitator_url": "https://facilitator.x402.rs/"
  },
  "endpoints": {
    "GET /api/":              { "description": "This document." },
    "GET /api/table/{name}":  { "description": "...", "response_format": "application/json" },
    "GET /api/query":         { "description": "...", "response_format": "application/vnd.apache.arrow.stream" }
  },
  "tables": [
    {
      "name": "uniswap_v3_pool_swap",
      "description": "Uniswap V3 pool swaps",
      "requires_payment": true,
      "details": "/api/table/uniswap_v3_pool_swap",
      "pricing": [
        {
          "model": "PerRow",
          "amount_per_item": "2000",
          "token_address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
          "chain": "84532",
          "pay_to": "0xE7a820f9E05e4a456A7567B79e433cc64A058Ae7"
        }
      ]
    }
  ]
}

MetadataPrice tags are intentionally omitted from the pricing array here — discovering them is the job of GET /api/table/{name}.


GET /api/query

Executes a SQL query against the database. The SQL is passed via the query URL parameter (URL-encoded).

Queries must conform to a restricted SQL dialect (“Simplified SQL”) whose AST permits only SELECT statements against a single table, with a limited set of WHERE, ORDER BY, and LIMIT expressions. JOINs, subqueries, GROUP BY, CTEs, window functions, and aggregates are rejected. See the SQL Parser page for the full grammar.

Request

curl --get http://localhost:4021/api/query \
  --data-urlencode "query=SELECT * FROM my_table WHERE col1 = 'value' LIMIT 10"

Query parameters

NameDescription
queryThe SQL statement to execute, URL-encoded.

200 OK — Arrow IPC

Binary Arrow IPC stream:

Content-Type: application/vnd.apache.arrow.stream

Parse with any Arrow library (PyArrow, apache-arrow in JS, arrow crate in Rust). See Response Formats for examples.

402 Payment Required

Returned when the table requires payment and no valid Payment-Signature header is present, or when verification/settlement fails.

Content-Type: application/json
Payment-Required: <base64-encoded JSON payload>
{
  "x402Version": 2,
  "error": "No crypto payment found. Implement x402 protocol...",
  "resource": {
    "url": "http://localhost:4021/api/query?query=SELECT%20*%20FROM%20uniswap_v3_pool_swap%20LIMIT%202",
    "description": "Uniswap v3 pool swaps - 2 rows",
    "mimeType": "application/vnd.apache.arrow.stream"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:84532",
      "amount": "4000",
      "payTo": "0xE7a820f9E05e4a456A7567B79e433cc64A058Ae7",
      "maxTimeoutSeconds": 300,
      "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
      "extra": { "name": "USDC", "version": "2" }
    }
  ]
}

Response Errors

400 Bad Request — missing/invalid query parameter, invalid SQL, unsupported table, or undecodable payment header. Plain text body.

500 Internal Server Error — database, serialization, or facilitator error. Plain text body.

Headers

HeaderDirectionDescription
Payment-RequiredResponseBase64-encoded payment requirements on 402
Payment-SignatureRequestBase64-encoded PaymentPayload (Step 2 of the x402 flow)
Content-Type: application/vnd.apache.arrow.streamResponseArrow IPC data on 200

GET /api/table/{name}

Returns full schema and payment-offer details for a specific table as JSON.

If the table has a MetadataPrice price tag, this endpoint requires payment via the x402 protocol before returning data — otherwise the metadata is returned freely.

Request

curl http://localhost:4021/api/table/my_table

Response (200 OK)

The serialized TablePaymentOffers:

{
  "table_name": "my_table",
  "price_tags": [
    {
      "pay_to": "0xE7a820f9E05e4a456A7567B79e433cc64A058Ae7",
      "pricing": { "model": "PerRow", "amount_per_item": "2000", "min_items": null, "max_items": null, "min_total_amount": null },
      "token": { "chain": "84532", "address": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", "decimals": 6, "transfer_method": "..." },
      "is_default": true
    }
  ],
  "requires_payment": true,
  "description": "My dataset",
  "schema": { "fields": [ ... ] }
}

Response (402 Payment Required) — when the table has a MetadataPrice tag and no valid Payment-Signature is provided. Same body shape as the 402 from GET /api/query, but with mimeType: "application/json" and the resource.url pointing at the metadata endpoint.

Response (404 Not Found)

{ "error": "Table 'unknown_table' not found" }

Response (400 Bad Request) — when the Payment-Signature header cannot be decoded or parsed. Plain text body.

Response (500 Internal Server Error) — facilitator failure or no matching payment offer. Plain text body.

Headers

HeaderDirectionDescription
Payment-RequiredResponseBase64-encoded payment requirements (on 402)
Payment-SignatureRequestBase64-encoded PaymentPayload (required for paid metadata)
Content-Type: application/jsonResponseAll success and 402 responses are JSON