{
  "openapi": "3.1.0",
  "info": {
    "title": "Tickerz Activity Score API",
    "version": "1.2.0",
    "description": "Public JSON API and signed webhooks for the Tickerz activity score. No API key for reads. Webhook signup uses email + HTTPS URL with a GET challenge. Keys say score since September 22 2026. The old heat keys (heat, heat_1h, heat_7d, peak_heat, heat_events, heat_halted, heat_at_open) are deprecated aliases with the same values and remain until at least 2026-12-31. heat_at_open equals peak_score (the peak, not the opening score); score_at_open is the opening score. The webhook entry HeatEvent (operationId heatWebhookDelivery) is kept as a deprecated duplicate of ScoreEvent for the same date. On 2026-09-23 the /api/changelog score_events[].kind value resolved became closed, for an event that has closed; the deprecated heat_events keeps resolved until at least 2026-12-31.",
    "contact": {
      "email": "desk@tickerz.com",
      "url": "https://tickerz.com"
    }
  },
  "servers": [
    {
      "url": "https://tickerz.com"
    }
  ],
  "tags": [
    {
      "name": "Terminal"
    },
    {
      "name": "Assets"
    },
    {
      "name": "Receipts"
    },
    {
      "name": "Questions",
      "description": "The referee: one sealed attention question per crypto event, graded at 24 hours against three nulls, Tickerz included."
    },
    {
      "name": "Webhooks"
    },
    {
      "name": "Status"
    },
    {
      "name": "Changelog"
    },
    {
      "name": "Machine tier",
      "description": "Deeper reads of the same record, built to be paid per call over x402. Closed for now: each route answers 503 with error tier_closed until the tier opens."
    }
  ],
  "paths": {
    "/api/board": {
      "get": {
        "tags": [
          "Terminal"
        ],
        "summary": "Full Terminal",
        "operationId": "getBoard",
        "responses": {
          "200": {
            "description": "Terminal snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BoardResponse"
                }
              }
            }
          },
          "503": {
            "description": "Halted; halted=true, assets empty",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BoardResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/asset/{symbol}": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "One asset",
        "operationId": "getAsset",
        "parameters": [
          {
            "name": "symbol",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "btc"
          }
        ],
        "responses": {
          "200": {
            "description": "Asset detail: asset, latest, vol_mult (measured volume multiple, null under a 14-day baseline), scores_30d (30 days of activity score readings, every fourth stored tick: hourly for crypto, every 40 minutes in market hours for stocks; oldest first, each ts and score), open_event and past_events (the latest 10 closed events, each with score_at_open and peak_score), spark_24h, context, venues (where it trades, checked nightly against each venue product list; plain unpaid links; us_available is false for Hyperliquid and Polymarket) and venues_checked_at. Deprecated aliases with the same values, remaining until at least 2026-12-31: heat_7d (the same readings as scores_30d in the old shape, each ts and heat) and peak_heat on events."
          }
        }
      }
    },
    "/api/base-rate/{symbol}": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "Base rate for the current move",
        "description": "What historically happened after a move like this asset's current one: the median, spread and share that beat the benchmark at 1, 7 and 30 days, next to an ordinary day. Only on days with an activity score of 70 or more, and only for groups that hold. Otherwise base_rate is null with a reason. Stocks are measured against SPY. Same as the MCP base_rate tool.",
        "operationId": "getBaseRate",
        "parameters": [
          {
            "name": "symbol",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "sol"
          }
        ],
        "responses": {
          "200": {
            "description": "The rate (symbol, move_24h, bucket, breadth, coin_in_study, n, n_dates, top_date_share, horizons for 1d, 7d and 30d, ordinary, edge_7d_pts, edge_7d_ci, plain, caveat, source; benchmark on stock rates only), or { symbol, base_rate: null, reason } when there is none: a score below 70, a withheld group, a reading that is not current, or the stock study."
          },
          "404": {
            "description": "not_listed"
          },
          "503": {
            "description": "halted"
          }
        }
      }
    },
    "/api/receipts": {
      "get": {
        "tags": [
          "Receipts"
        ],
        "summary": "Closed events and their receipts",
        "operationId": "getReceipts",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Receipt list: the most recent closed events (status cooling or resolved), newest first, each with score_at_open, peak_score, receipts at 24h, 7d and 30d (ret_pct and resolved_at null until each resolves; benchmark is BTC for crypto and SPY for stocks, and benchmark_ret_pct is its return over the same window, null until filled) and proofs. peak_heat on each event is the deprecated alias of peak_score, same value, remaining until at least 2026-12-31."
          }
        }
      }
    },
    "/api/webhooks/subscribe": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Subscribe a webhook URL",
        "operationId": "subscribeWebhook",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookSubscribeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received. A new email gets its signing secret once. An email already on file is left as it is and gets the same ok answer without a secret, so the endpoint does not say who is subscribed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookSubscribeResponse"
                }
              }
            }
          },
          "400": {
            "description": "invalid_json | invalid_email | invalid_url | challenge_failed"
          },
          "403": {
            "description": "cross_site: the request came from another site"
          },
          "415": {
            "description": "not_json: content-type must be application/json"
          },
          "429": {
            "description": "rate_limited: five signups per address per ten minutes"
          },
          "500": {
            "description": "save_failed | confirm_failed"
          },
          "503": {
            "description": "unavailable: the database is not connected or could not be read"
          }
        }
      }
    },
    "/api/webhooks/confirm": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Retry GET challenge with confirm token",
        "operationId": "confirmWebhook",
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Confirmed"
          },
          "400": {
            "description": "challenge_failed"
          },
          "404": {
            "description": "not_found"
          }
        }
      }
    },
    "/api/receipts/dataset": {
      "get": {
        "tags": [
          "Receipts"
        ],
        "summary": "Open dataset of closed events",
        "description": "One flat row per closed event (cooling or resolved); returns stay null until each receipt resolves. Includes hidden assets with display=false. Omits trigger z-scores. Paginate with limit and offset. First export window starts 2026-08-27.",
        "operationId": "getReceiptsDataset",
        "parameters": [
          {
            "name": "since",
            "in": "query",
            "description": "YYYY-MM-DD, clamped to a minimum of 2026-08-27",
            "schema": {
              "type": "string",
              "format": "date",
              "default": "2026-08-27"
            }
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "csv"
              ],
              "default": "json"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 5000,
              "default": 1000
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Dataset page. CSV when format=csv, with Content-Disposition attachment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceiptsDatasetResponse"
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string",
                  "description": "Header row then one row per event, same columns as rows[]"
                }
              }
            }
          },
          "503": {
            "description": "Database not connected; halted=true"
          }
        }
      }
    },
    "/api/receipts/proof": {
      "get": {
        "tags": [
          "Receipts"
        ],
        "summary": "OpenTimestamps proof for one event record",
        "description": "JSON metadata for the stamp, or the .ots file with format=ots. Verify at opentimestamps.org or with the ots CLI. Until a Bitcoin height is known the stamp is calendar-pending. horizon=open is the event as called. New events are stamped within about an hour of open. Events already on the record when open stamping shipped on September 22 2026 were stamped later, some after their outcome, so compare stamped_at with opened_at. 24h, 7d and 30d are the resolved receipts.",
        "operationId": "getReceiptProof",
        "parameters": [
          {
            "name": "event_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "horizon",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "24h",
                "7d",
                "30d"
              ]
            }
          },
          {
            "name": "format",
            "in": "query",
            "description": "ots downloads the proof file",
            "schema": {
              "type": "string",
              "enum": [
                "ots"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Proof metadata, or the .ots file when format=ots",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceiptProof"
                }
              },
              "application/vnd.opentimestamps.ots": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "event_id and horizon required"
          },
          "404": {
            "description": "not_found"
          }
        }
      }
    },
    "/api/status": {
      "get": {
        "tags": [
          "Status"
        ],
        "summary": "Public Terminal health",
        "description": "ok, degraded, or halted from Terminal freshness, receipt clocks and proofs. HTML twin at /status.",
        "operationId": "getStatus",
        "responses": {
          "200": {
            "description": "ok or degraded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusResponse"
                }
              }
            }
          },
          "503": {
            "description": "halted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/changelog": {
      "get": {
        "tags": [
          "Changelog"
        ],
        "summary": "Ship notes and recent events",
        "description": "Curated Terminal ship notes plus recent open and closed events. HTML twin at /changelog.",
        "operationId": "getChangelog",
        "responses": {
          "200": {
            "description": "Changelog",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChangelogResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/history/{symbol}": {
      "get": {
        "tags": [
          "Machine tier"
        ],
        "summary": "Full history for one asset",
        "description": "Every stored tick for one asset: activity score, price, 24h volume and 24h move, oldest first. From 2026-09-29, readings older than 45 days keep one per hour. Machine tier: closed for now, so the route answers 503 with error tier_closed. When the tier opens it is paid per call over x402 and a 402 carries the price.",
        "operationId": "getHistory",
        "parameters": [
          {
            "name": "symbol",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 365,
              "default": 90
            }
          }
        ],
        "responses": {
          "200": {
            "description": "History",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "asset": {
                      "type": "object",
                      "properties": {
                        "symbol": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "class": {
                          "type": "string"
                        }
                      }
                    },
                    "since": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "points": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "ts": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "score": {
                            "type": "integer",
                            "nullable": true,
                            "description": "Activity score at this tick, null when the tick has a snapshot and no score"
                          },
                          "heat": {
                            "type": "integer",
                            "nullable": true,
                            "deprecated": true,
                            "description": "Deprecated alias of score, same value. Remains until at least 2026-12-31."
                          },
                          "price": {
                            "type": "number",
                            "nullable": true
                          },
                          "vol_24h": {
                            "type": "number",
                            "nullable": true
                          },
                          "move_24h": {
                            "type": "number",
                            "nullable": true
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Payment required, once the machine tier opens: the tier is on and the request carried no valid payment. The PaymentRequired object (x402 version 2) is base64 in the PAYMENT-REQUIRED header and mirrored as the JSON body: amount in USDC atomic units, network as a CAIP-2 id, the pay-to address and the resource.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "x402Version": {
                      "type": "integer",
                      "enum": [
                        2
                      ]
                    },
                    "error": {
                      "type": "string"
                    },
                    "resource": {
                      "type": "object"
                    },
                    "accepts": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Symbol not listed"
          },
          "503": {
            "description": "The machine tier is closed (error tier_closed, the state today)"
          }
        }
      }
    },
    "/api/board/at": {
      "get": {
        "tags": [
          "Machine tier"
        ],
        "summary": "The whole board at one moment",
        "description": "Every displayed asset with a score in the two hours before the given moment: the newest activity score, price, move and volume at or before it, sorted by activity score. Machine tier: closed for now, so the route answers 503 with error tier_closed. When the tier opens it is paid per call over x402 and a 402 carries the price.",
        "operationId": "getBoardAt",
        "parameters": [
          {
            "name": "ts",
            "in": "query",
            "description": "ISO 8601 moment, default one hour ago",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Board at that moment",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "assets": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "symbol": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "class": {
                            "type": "string"
                          },
                          "ts": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "score": {
                            "type": "integer",
                            "description": "Newest activity score at or before the moment"
                          },
                          "heat": {
                            "type": "integer",
                            "deprecated": true,
                            "description": "Deprecated alias of score, same value. Remains until at least 2026-12-31."
                          },
                          "price": {
                            "type": "number",
                            "nullable": true
                          },
                          "move_24h": {
                            "type": "number",
                            "nullable": true
                          },
                          "vol_24h": {
                            "type": "number",
                            "nullable": true
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad ts"
          },
          "402": {
            "description": "Payment required, once the machine tier opens: the tier is on and the request carried no valid payment. The PaymentRequired object (x402 version 2) is base64 in the PAYMENT-REQUIRED header and mirrored as the JSON body: amount in USDC atomic units, network as a CAIP-2 id, the pay-to address and the resource.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "x402Version": {
                      "type": "integer",
                      "enum": [
                        2
                      ]
                    },
                    "error": {
                      "type": "string"
                    },
                    "resource": {
                      "type": "object"
                    },
                    "accepts": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Database not connected, or the machine tier is closed (error tier_closed, the state today)"
          }
        }
      }
    },
    "/api/receipts/full": {
      "get": {
        "tags": [
          "Machine tier"
        ],
        "summary": "Every receipt with its proof",
        "description": "The open dataset rows plus, for the open record and each resolved horizon, the canonical JSON that was hashed, the SHA-256 digest, the Bitcoin block height once upgraded, and the OpenTimestamps proof as base64. Machine tier: closed for now, so the route answers 503 with error tier_closed. When the tier opens it is paid per call over x402 and a 402 carries the price.",
        "operationId": "getReceiptsFull",
        "parameters": [
          {
            "name": "since",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date",
              "default": "2026-08-27"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 200
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Rows with proofs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "rows": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "next_offset": {
                      "type": "integer",
                      "nullable": true
                    },
                    "halted": {
                      "type": "boolean"
                    },
                    "since": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Payment required, once the machine tier opens: the tier is on and the request carried no valid payment. The PaymentRequired object (x402 version 2) is base64 in the PAYMENT-REQUIRED header and mirrored as the JSON body: amount in USDC atomic units, network as a CAIP-2 id, the pay-to address and the resource.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "x402Version": {
                      "type": "integer",
                      "enum": [
                        2
                      ]
                    },
                    "error": {
                      "type": "string"
                    },
                    "resource": {
                      "type": "object"
                    },
                    "accepts": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Database not connected, or the machine tier is closed (error tier_closed, the state today)"
          }
        }
      }
    },
    "/api/questions": {
      "get": {
        "tags": [
          "Questions"
        ],
        "summary": "The referee's questions",
        "description": "Every question, newest first, with the nulls frozen at creation, Tickerz's answer, the outcome, the seal and calibration over every resolved question. The crowd split is null until answers close.",
        "operationId": "listQuestions",
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "resolved",
                "all"
              ],
              "default": "all"
            }
          },
          {
            "name": "symbol",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Questions and calibration",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuestionsResponse"
                }
              }
            }
          },
          "503": {
            "description": "halted"
          }
        }
      }
    },
    "/api/questions/{id}": {
      "get": {
        "tags": [
          "Questions"
        ],
        "summary": "One question with its proofs",
        "description": "The question's canonical_json and .ots proof are served at once; each answer batch's proof waits until answers close. sha256(canonical_json) equals digest_sha256.",
        "operationId": "getQuestion",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The question",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuestionDetail"
                }
              }
            }
          },
          "404": {
            "description": "not_found"
          }
        }
      }
    },
    "/api/questions/{id}/answer": {
      "post": {
        "tags": [
          "Questions"
        ],
        "summary": "Answer an open question",
        "description": "No key, no login. One answer per caller per question (a keyed hash of the question, address and user agent, never published) and at most 3 answers per question from one address, whatever the user agent (IPv6 counted by its /64). A repeat returns 200 with already_answered true and does not echo the first answer. Answers close 4 hours after the question opens. 20 answers per minute per address. No ranking, no prizes. The body must be JSON. Unlike the reads, this route sends no CORS headers, and a browser call marked cross-site is refused, so another site's page cannot answer from its visitors' browsers.",
        "operationId": "answerQuestion",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnswerRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Already answered by this caller. The first answer stands and is not echoed back",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnswerRepeat"
                }
              }
            }
          },
          "201": {
            "description": "Recorded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnswerResponse"
                }
              }
            }
          },
          "400": {
            "description": "error and message",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "cross_site: sent from another site's page",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "error and message",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "address_cap: this address has given 3 answers to this question",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "410": {
            "description": "error and message",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "415": {
            "description": "not_json: the body must be application/json",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "error and message",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/indices/proof": {
      "get": {
        "tags": [
          "Receipts"
        ],
        "summary": "OpenTimestamps proof for one daily index seal",
        "description": "The seal of one day of the Tickerz Index: every complete period written or revised since the seal before, hashed and stamped in Bitcoin. JSON metadata, or the .ots file with format=ots. Verify sha256(canonical_json) against digest_sha256 and check the .ots file with the OpenTimestamps client or opentimestamps.org. Until a Bitcoin height is known the stamp is calendar-pending.",
        "operationId": "getIndexProof",
        "parameters": [
          {
            "name": "day",
            "in": "query",
            "description": "YYYY-MM-DD, the seal day; the newest seal when omitted",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "format",
            "in": "query",
            "description": "ots downloads the proof file as tickerz-seal-{day}.ots",
            "schema": {
              "type": "string",
              "enum": [
                "ots"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Proof metadata, or the .ots file when format=ots",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IndexProof"
                }
              },
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "bad_day"
          },
          "404": {
            "description": "not_found: no seal for that day"
          },
          "429": {
            "description": "rate_limited"
          },
          "500": {
            "description": "proof_unreadable"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "BoardResponse": {
        "type": "object",
        "properties": {
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "halted": {
            "type": "boolean"
          },
          "assets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BoardAsset"
            }
          },
          "breadth": {
            "type": [
              "object",
              "null"
            ],
            "description": "How many scored, current coins are unusual right now. Crypto only. Null when halted or when no coin is scored.",
            "properties": {
              "unusual": {
                "type": "integer",
                "description": "Scored, current crypto with an activity score of 70 or more"
              },
              "scored": {
                "type": "integer",
                "description": "Crypto with a score whose latest reading is not stale"
              },
              "share": {
                "type": "number",
                "description": "unusual / scored, three decimals"
              },
              "band": {
                "type": "string",
                "enum": [
                  "lone",
                  "mid",
                  "crowd"
                ],
                "description": "lone under 3%, crowd at 30% or more, mid between. The bands the Attention fades study uses."
              }
            }
          }
        }
      },
      "BoardAsset": {
        "type": "object",
        "required": [
          "symbol",
          "name",
          "class",
          "price",
          "move_24h",
          "score",
          "ts"
        ],
        "properties": {
          "symbol": {
            "type": "string",
            "example": "BTC"
          },
          "name": {
            "type": "string"
          },
          "class": {
            "type": "string",
            "enum": [
              "crypto",
              "equity"
            ]
          },
          "mcap_rank": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Rank by market cap; null for equities"
          },
          "price": {
            "type": "number",
            "description": "USD"
          },
          "move_24h": {
            "type": "number",
            "description": "24h move, percent"
          },
          "score": {
            "type": [
              "number",
              "null"
            ],
            "description": "Activity score, 0 to 100. Null while the asset builds its baseline."
          },
          "score_1h": {
            "type": [
              "number",
              "null"
            ],
            "description": "Activity score one hour earlier"
          },
          "heat": {
            "type": [
              "number",
              "null"
            ],
            "description": "Deprecated alias of score, same value. Remains until at least 2026-12-31.",
            "deprecated": true
          },
          "heat_1h": {
            "type": [
              "number",
              "null"
            ],
            "description": "Deprecated alias of score_1h, same value. Remains until at least 2026-12-31.",
            "deprecated": true
          },
          "z_vol": {
            "type": [
              "number",
              "null"
            ],
            "description": "Volume z-score against the asset's own 30 day baseline"
          },
          "z_move": {
            "type": [
              "number",
              "null"
            ],
            "description": "Absolute move z-score against the asset's own 30 day baseline"
          },
          "spark": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "number"
            },
            "description": "Hourly peak activity score over the last 24 hours, oldest first"
          },
          "event_open": {
            "type": "boolean",
            "description": "An event is open on this asset"
          },
          "ts": {
            "type": "string",
            "format": "date-time",
            "description": "Snapshot time"
          },
          "driver_tag": {
            "type": [
              "string",
              "null"
            ],
            "description": "Set only while an event is open, once classified. One of idiosyncratic_news, macro_or_sector_move, listing_or_calendar_event, social_and_hype_driven, technical, unclassified (shown as Driver: not identified). A tag cites a headline or filing, except macro_or_sector_move set by a rule (a fund, or a move across much of the market), which carries no source and a null confidence. Events tagged by the first pipeline, through September 22 2026, may carry a tag with no source. Advisory, not advice."
          },
          "driver_confidence": {
            "type": [
              "number",
              "null"
            ],
            "description": "Classifier confidence for driver_tag, 0 to 1. Null when a rule set the tag."
          },
          "vol_mult": {
            "type": [
              "number",
              "null"
            ],
            "description": "Measured volume multiple, one decimal: this snapshot's 24h volume over the asset's 30-day baseline mean as of the snapshot. Null while the baseline has fewer than 14 days."
          },
          "stale": {
            "type": "boolean",
            "description": "True when the reading is not current: crypto more than 2 hours old; equities more than 2 hours behind the newest equity tick, or older than 4 days"
          },
          "sector": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "ReceiptsDatasetRow": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "string",
            "format": "uuid"
          },
          "opened_at": {
            "type": "string",
            "format": "date-time"
          },
          "symbol": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "class": {
            "type": "string",
            "enum": [
              "crypto",
              "equity"
            ]
          },
          "display": {
            "type": "boolean",
            "description": "false for hidden assets"
          },
          "heat_at_open": {
            "type": "number",
            "deprecated": true,
            "description": "Deprecated. Despite the name this is the peak activity score while the event was open, equal to peak_score. Use score_at_open for the opening score. Remains until at least 2026-12-31."
          },
          "reference_price": {
            "type": "number",
            "description": "Frozen price at open, USD"
          },
          "ret_24h": {
            "type": [
              "number",
              "null"
            ],
            "description": "Percent return at 24h, null until resolved"
          },
          "resolved_24h": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "ret_7d": {
            "type": [
              "number",
              "null"
            ]
          },
          "resolved_7d": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "ret_30d": {
            "type": [
              "number",
              "null"
            ]
          },
          "resolved_30d": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "score_at_open": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Activity score of the tick that opened the event"
          },
          "peak_score": {
            "type": "number",
            "description": "Highest activity score while the event was open"
          },
          "benchmark": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "BTC",
              "SPY",
              null
            ],
            "description": "BTC for crypto, SPY for stocks. Null until the benchmark fill has run"
          },
          "benchmark_ret_24h": {
            "type": [
              "number",
              "null"
            ],
            "description": "The benchmark's percent return over the same window as ret_24h, null until filled"
          },
          "benchmark_ret_7d": {
            "type": [
              "number",
              "null"
            ],
            "description": "The benchmark's percent return over the same window as ret_7d, null until filled"
          },
          "benchmark_ret_30d": {
            "type": [
              "number",
              "null"
            ],
            "description": "The benchmark's percent return over the same window as ret_30d, null until filled"
          }
        }
      },
      "ReceiptsDatasetResponse": {
        "type": "object",
        "properties": {
          "rows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReceiptsDatasetRow"
            }
          },
          "next_offset": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Next page offset, or null when done"
          },
          "halted": {
            "type": "boolean",
            "description": "true when the database is not connected"
          },
          "since": {
            "type": "string",
            "format": "date",
            "description": "Effective since after clamping"
          }
        }
      },
      "ReceiptProof": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "string",
            "format": "uuid"
          },
          "horizon": {
            "type": "string",
            "enum": [
              "open",
              "24h",
              "7d",
              "30d"
            ],
            "description": "open is the event as called at open; 24h, 7d and 30d are the resolved receipts"
          },
          "digest_sha256": {
            "type": "string",
            "description": "SHA-256 of canonical_json"
          },
          "canonical": {
            "type": "object",
            "description": "The stamped record. Receipts: event_id, symbol, opened_at, open_price, horizon, resolved_at, ret_pct. Open: event_id, symbol, opened_at, open_price, horizon, score_at_open, trigger_z_vol, trigger_z_move. Stored as jsonb, so key order here is not the hashed order; use canonical_json"
          },
          "canonical_json": {
            "type": [
              "string",
              "null"
            ],
            "description": "The exact bytes that were hashed: compact JSON with keys in the documented order. sha256(canonical_json) equals digest_sha256"
          },
          "bitcoin_height": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Bitcoin block height once the stamp upgrades, else null"
          },
          "bitcoin_block_time": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "stamped_at": {
            "type": "string",
            "format": "date-time"
          },
          "upgraded_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "ots_url": {
            "type": "string",
            "description": "Same endpoint with format=ots"
          },
          "verify": {
            "type": "string",
            "format": "uri",
            "example": "https://opentimestamps.org"
          }
        }
      },
      "StatusResponse": {
        "type": "object",
        "properties": {
          "state": {
            "type": "string",
            "enum": [
              "ok",
              "degraded",
              "halted"
            ]
          },
          "checked_at": {
            "type": "string",
            "format": "date-time"
          },
          "board": {
            "type": "object",
            "properties": {
              "halted": {
                "type": "boolean"
              },
              "updated_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "age_minutes": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "asset_count": {
                "type": "integer"
              },
              "scored_count": {
                "type": "integer"
              }
            }
          },
          "receipts": {
            "type": "object",
            "properties": {
              "halted": {
                "type": "boolean"
              },
              "recent_count": {
                "type": "integer"
              },
              "resolved_7d": {
                "type": "integer",
                "description": "Receipts resolved in the last 7 days, any horizon"
              }
            }
          },
          "proofs": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "pending": {
                "type": "integer"
              },
              "stuck": {
                "type": "integer"
              },
              "oldest_hours": {
                "type": [
                  "number",
                  "null"
                ]
              }
            }
          },
          "receipt_lag": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "overdue": {
                "type": "integer"
              },
              "oldest_overdue_min": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "late": {
                "type": "integer"
              },
              "resolved_checked": {
                "type": "integer"
              }
            }
          },
          "checks": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "ok": {
                  "type": "boolean"
                },
                "detail": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "ChangelogEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "kind": {
            "type": "string",
            "enum": [
              "open",
              "closed",
              "resolved"
            ],
            "description": "open, or closed in score_events (its receipts may still be pending). heat_events carries the old value resolved for a closed event."
          },
          "symbol": {
            "type": "string"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "opened_at": {
            "type": "string",
            "format": "date-time"
          },
          "peak_score": {
            "type": [
              "number",
              "null"
            ],
            "description": "Peak activity score during the event"
          },
          "peak_heat": {
            "type": [
              "number",
              "null"
            ],
            "description": "Deprecated alias of peak_score, same value. Remains until at least 2026-12-31.",
            "deprecated": true
          },
          "score_at_open": {
            "type": [
              "number",
              "null"
            ],
            "description": "Activity score of the tick that opened the event"
          }
        }
      },
      "ChangelogResponse": {
        "type": "object",
        "properties": {
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "ships": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "pr": {
                  "type": "integer"
                },
                "title": {
                  "type": "string"
                },
                "summary": {
                  "type": "string"
                }
              }
            }
          },
          "score_events": {
            "type": "array",
            "description": "Recent open and closed events",
            "items": {
              "$ref": "#/components/schemas/ChangelogEvent"
            }
          },
          "score_halted": {
            "type": "boolean",
            "description": "true when activity-score feeds are unavailable"
          },
          "heat_events": {
            "type": "array",
            "deprecated": true,
            "description": "Deprecated alias of score_events, the same events with kind resolved where score_events says closed. Remains until at least 2026-12-31.",
            "items": {
              "$ref": "#/components/schemas/ChangelogEvent"
            }
          },
          "heat_halted": {
            "type": "boolean",
            "deprecated": true,
            "description": "Deprecated alias of score_halted, same value. Remains until at least 2026-12-31."
          }
        }
      },
      "WebhookSubscribeRequest": {
        "type": "object",
        "required": [
          "email",
          "url"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS only"
          }
        }
      },
      "WebhookSubscribeResponse": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "confirmed": {
            "type": "boolean"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "secret": {
            "type": "string",
            "description": "HMAC-SHA256 key; shown once"
          },
          "verify": {
            "type": "string"
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "required": [
          "id",
          "type",
          "created_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "event_opened",
              "receipt_resolved"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "type": "object",
            "required": [
              "symbol",
              "event_id"
            ],
            "properties": {
              "symbol": {
                "type": "string"
              },
              "score": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Activity score. On receipt_resolved, the score that opened the event"
              },
              "heat": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Deprecated alias of score, same value. Remains until at least 2026-12-31.",
                "deprecated": true
              },
              "event_id": {
                "type": "string",
                "format": "uuid"
              },
              "horizon": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "24h | 7d | 30d on receipt_resolved; null on event_opened"
              },
              "text": {
                "type": "string"
              }
            }
          }
        },
        "description": "POSTed to the subscriber URL. Headers: X-Tickerz-Signature (sha256=<hex>), X-Tickerz-Delivery, X-Tickerz-Event."
      },
      "Question": {
        "type": "object",
        "description": "One question. crowd and grades are null until answers close; caller identities are never served.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "event_id": {
            "type": "string",
            "format": "uuid"
          },
          "symbol": {
            "type": "string"
          },
          "statement": {
            "type": "string",
            "example": "$HBAR reads 40 or more at Sep 24, 14:15 UTC."
          },
          "threshold": {
            "type": "integer",
            "example": 40
          },
          "template": {
            "type": "string",
            "example": "score_24h"
          },
          "answers": {
            "type": "object",
            "description": "Answer key to label",
            "properties": {
              "at_or_above": {
                "type": "string"
              },
              "below": {
                "type": "string"
              }
            }
          },
          "state": {
            "type": "string",
            "enum": [
              "open",
              "closed",
              "resolved",
              "void"
            ]
          },
          "accepting_answers": {
            "type": "boolean"
          },
          "event_opened_at": {
            "type": "string",
            "format": "date-time"
          },
          "opens_at": {
            "type": "string",
            "format": "date-time"
          },
          "closes_at": {
            "type": "string",
            "format": "date-time",
            "description": "Answers close 4 hours after opens_at"
          },
          "resolves_at": {
            "type": "string",
            "format": "date-time",
            "description": "event_opened_at plus 24 hours, cut to the whole minute"
          },
          "at_open": {
            "type": "object",
            "properties": {
              "score": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "vol_mult": {
                "type": [
                  "number",
                  "null"
                ]
              }
            }
          },
          "nulls": {
            "type": "object",
            "properties": {
              "base_rate": {
                "type": "object",
                "properties": {
                  "answer": {
                    "type": "string",
                    "enum": [
                      "at_or_above",
                      "below"
                    ]
                  },
                  "hits": {
                    "type": "integer"
                  },
                  "n": {
                    "type": "integer"
                  },
                  "share": {
                    "type": [
                      "number",
                      "null"
                    ]
                  }
                }
              },
              "persistence": {
                "type": "object",
                "properties": {
                  "answer": {
                    "type": "string",
                    "enum": [
                      "at_or_above",
                      "below"
                    ]
                  },
                  "score": {
                    "type": "integer"
                  },
                  "ts": {
                    "type": "string",
                    "format": "date-time"
                  }
                }
              },
              "always": {
                "type": "object",
                "properties": {
                  "answer": {
                    "type": "string",
                    "enum": [
                      "at_or_above",
                      "below"
                    ]
                  }
                }
              }
            }
          },
          "tickerz": {
            "type": "object",
            "properties": {
              "answer": {
                "type": "string",
                "enum": [
                  "at_or_above",
                  "below"
                ]
              },
              "rule": {
                "type": "string",
                "enum": [
                  "base_rate"
                ]
              }
            }
          },
          "answers_count": {
            "type": "integer",
            "description": "Answers from outside Tickerz so far, agents left out"
          },
          "crowd": {
            "type": [
              "object",
              "null"
            ],
            "description": "Null until answers close. Agents never count in it",
            "properties": {
              "at_or_above": {
                "type": "integer"
              },
              "below": {
                "type": "integer"
              },
              "n": {
                "type": "integer"
              },
              "majority": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "at_or_above",
                  "below",
                  null
                ]
              },
              "mean_probability": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "n_probability": {
                "type": "integer"
              }
            }
          },
          "agents_count": {
            "type": "integer",
            "description": "Answers from agents so far, counted apart from the crowd"
          },
          "agents": {
            "type": [
              "object",
              "null"
            ],
            "description": "Agents' answers, apart from the crowd. Null until answers close",
            "properties": {
              "n": {
                "type": "integer"
              },
              "labeled": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "label": {
                      "type": "string"
                    },
                    "answer": {
                      "type": "string",
                      "enum": [
                        "at_or_above",
                        "below"
                      ]
                    },
                    "probability": {
                      "type": [
                        "number",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "outcome": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "answer": {
                "type": "string",
                "enum": [
                  "at_or_above",
                  "below",
                  "void"
                ]
              },
              "score": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "reading_ts": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "resolved_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              }
            }
          },
          "grades": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "crowd": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "tickerz": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Null when the question was not sealed before answers closed"
              },
              "base_rate": {
                "type": "boolean"
              },
              "persistence": {
                "type": "boolean"
              },
              "always": {
                "type": "boolean"
              }
            }
          },
          "seal": {
            "type": "object",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "pending",
                  "stamped",
                  "confirmed"
                ]
              },
              "sealed_before_close": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "False when no seal was made before answers closed; Tickerz is then not graded on the question. Null while answers are open and no seal exists yet"
              },
              "digest_sha256": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "stamped_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "bitcoin_height": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "bitcoin_block_time": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "The confirming block's header time"
              }
            }
          },
          "answer_batches": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "n_answers": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "digest_sha256": {
                  "type": "string"
                },
                "stamped_at": {
                  "type": "string",
                  "format": "date-time"
                },
                "bitcoin_height": {
                  "type": [
                    "integer",
                    "null"
                  ]
                }
              }
            }
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "QuestionCalibration": {
        "type": "object",
        "description": "Hit rates over every resolved question. A tie has no crowd majority and is left out of the crowd's n; a question not sealed before answers closed is left out of Tickerz's n. Void questions are counted apart.",
        "properties": {
          "resolved": {
            "type": "integer"
          },
          "void": {
            "type": "integer"
          },
          "crowd": {
            "type": "object",
            "properties": {
              "hits": {
                "type": "integer"
              },
              "n": {
                "type": "integer"
              }
            }
          },
          "tickerz": {
            "type": "object",
            "properties": {
              "hits": {
                "type": "integer"
              },
              "n": {
                "type": "integer"
              }
            }
          },
          "base_rate": {
            "type": "object",
            "properties": {
              "hits": {
                "type": "integer"
              },
              "n": {
                "type": "integer"
              }
            }
          },
          "persistence": {
            "type": "object",
            "properties": {
              "hits": {
                "type": "integer"
              },
              "n": {
                "type": "integer"
              }
            }
          },
          "always": {
            "type": "object",
            "properties": {
              "hits": {
                "type": "integer"
              },
              "n": {
                "type": "integer"
              }
            }
          }
        }
      },
      "QuestionsResponse": {
        "type": "object",
        "properties": {
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "state": {
            "type": "string",
            "enum": [
              "open",
              "resolved",
              "all"
            ]
          },
          "symbol": {
            "type": [
              "string",
              "null"
            ]
          },
          "questions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Question"
            }
          },
          "calibration": {
            "$ref": "#/components/schemas/QuestionCalibration"
          }
        }
      },
      "QuestionDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Question"
          },
          {
            "type": "object",
            "properties": {
              "proofs": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "kind": {
                      "type": "string",
                      "enum": [
                        "question",
                        "answers"
                      ]
                    },
                    "digest_sha256": {
                      "type": "string"
                    },
                    "canonical_json": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The exact hashed text. For an answer batch, null until answers close"
                    },
                    "n_answers": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "bitcoin_height": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "bitcoin_block_time": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "stamped_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "ots_base64": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "AnswerRequest": {
        "type": "object",
        "required": [
          "answer"
        ],
        "properties": {
          "answer": {
            "type": "string",
            "enum": [
              "at_or_above",
              "below"
            ],
            "description": "at_or_above: it reads 40 or more"
          },
          "probability": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Optional: the chance it reads 40 or more. Must agree with the answer; 0.5 fits either"
          },
          "agent": {
            "type": "string",
            "maxLength": 32,
            "description": "Optional: the name of an agent answering for someone, e.g. Muse. 1 to 32 letters, digits, spaces, dots, hyphens or underscores. The answer is stored as an agent's, never counts in the crowd split, and is shown by name beside the crowd once answers close"
          }
        }
      },
      "AnswerResponse": {
        "type": "object",
        "properties": {
          "answer_id": {
            "type": "string",
            "format": "uuid"
          },
          "question_id": {
            "type": "string",
            "format": "uuid"
          },
          "answer": {
            "type": "string",
            "enum": [
              "at_or_above",
              "below"
            ]
          },
          "probability": {
            "type": [
              "number",
              "null"
            ]
          },
          "answered_at": {
            "type": "string",
            "format": "date-time"
          },
          "closes_at": {
            "type": "string",
            "format": "date-time"
          },
          "split_shown_at": {
            "type": "string",
            "format": "date-time"
          },
          "already_answered": {
            "type": "boolean",
            "const": false,
            "description": "False on a new answer; a repeat gets AnswerRepeat"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "AnswerRepeat": {
        "type": "object",
        "description": "A repeat from the same caller. The first answer is not sent back: two people behind one address and one browser share a caller hash.",
        "properties": {
          "question_id": {
            "type": "string",
            "format": "uuid"
          },
          "closes_at": {
            "type": "string",
            "format": "date-time"
          },
          "split_shown_at": {
            "type": "string",
            "format": "date-time"
          },
          "already_answered": {
            "type": "boolean",
            "const": true
          },
          "message": {
            "type": "string"
          }
        }
      },
      "IndexProof": {
        "type": "object",
        "properties": {
          "day": {
            "type": "string",
            "format": "date"
          },
          "digest_sha256": {
            "type": "string",
            "description": "SHA-256 of canonical_json"
          },
          "canonical_json": {
            "type": "string",
            "description": "the exact bytes that were hashed"
          },
          "stamped_at": {
            "type": "string",
            "format": "date-time"
          },
          "bitcoin_height": {
            "type": [
              "integer",
              "null"
            ]
          },
          "bitcoin_block_time": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "ots_proof_base64": {
            "type": "string"
          },
          "ots_url": {
            "type": "string"
          },
          "verify": {
            "type": "string"
          }
        }
      }
    }
  },
  "webhooks": {
    "ScoreEvent": {
      "post": {
        "summary": "Event or receipt push",
        "operationId": "scoreWebhookDelivery",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookDelivery"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted"
          }
        }
      }
    },
    "HeatEvent": {
      "post": {
        "summary": "Event or receipt push (deprecated name)",
        "operationId": "heatWebhookDelivery",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookDelivery"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted"
          }
        },
        "deprecated": true,
        "description": "Deprecated duplicate of ScoreEvent, the same delivery under its old name. Kept until at least 2026-12-31 so generated clients keep their identifiers. Use ScoreEvent."
      }
    }
  }
}
