{
  "openapi": "3.1.0",
  "info": {
    "title": "ClearMarket API",
    "version": "0.2.0",
    "description": "Reference data layer for prediction markets: cross-venue event linking, Resolution Clarity Grades (A/B/C), committed resolution sources with provenance, jurisdiction eligibility screens, live marks, and CM Signal wires across Kalshi and Polymarket. Open access, no key required (optional free key raises rate limits). Attribution required: clearmarket.fyi. Same data via MCP (https://api.clearmarket.fyi/mcp) and A2A (https://api.clearmarket.fyi/a2a).",
    "contact": {
      "name": "ClearMarket",
      "url": "https://clearmarket.fyi/for-data/"
    }
  },
  "servers": [
    {
      "url": "https://api.clearmarket.fyi"
    }
  ],
  "externalDocs": {
    "description": "Human docs, schema tour, and grading methodology",
    "url": "https://clearmarket.fyi/for-data/"
  },
  "paths": {
    "/": {
      "get": {
        "operationId": "serviceInfo",
        "summary": "Service status, coverage counts, and valid filter values",
        "description": "Returns live event/market counts plus the valid category/platform/grade filter vocabulary so a client can discover query values without guessing.",
        "responses": {
          "200": {
            "description": "Service info",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/v1/events": {
      "get": {
        "operationId": "listEvents",
        "summary": "List graded events",
        "parameters": [
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "economics",
                "financials",
                "crypto",
                "companies",
                "technology",
                "politics",
                "geopolitics",
                "health",
                "climate"
              ]
            }
          },
          {
            "name": "platform",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "kalshi",
                "polymarket"
              ]
            }
          },
          {
            "name": "grade",
            "in": "query",
            "description": "Resolution Clarity Grade of the primary market",
            "schema": {
              "type": "string",
              "enum": [
                "A",
                "B",
                "C"
              ]
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Token-AND search across question and tags",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "active = has at least one open market; resolved = none",
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "active",
                "resolved"
              ],
              "default": "all"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paged event list. Unknown filter values return an empty page plus a notice naming the valid set.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "rows in this page"
                    },
                    "total": {
                      "type": "integer",
                      "description": "full count under the active filters"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    },
                    "events": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      }
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/v1/events/{slug}": {
      "get": {
        "operationId": "getEvent",
        "summary": "One event with all linked markets, cross-venue prices, catalysts, and resolution detail",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Event slug OR ClearMarket event_id — both resolve",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "detail",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "full",
                "concise"
              ],
              "default": "full"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Event fields FLATTENED at the top level (not wrapped in an `event` key), plus linked markets and resolution log",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Event"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "markets": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Market"
                          }
                        },
                        "resolution_log": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/ResolutionLogEntry"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Unknown slug/event_id"
          }
        }
      }
    },
    "/v1/markets/{id}": {
      "get": {
        "operationId": "getMarket",
        "summary": "One market by ClearMarket market_id",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Market",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Market"
                }
              }
            }
          },
          "404": {
            "description": "Unknown market_id"
          }
        }
      }
    },
    "/v1/markets/movers": {
      "get": {
        "operationId": "listMovers",
        "summary": "Day-over-day volume movers across all tracked markets",
        "parameters": [
          {
            "name": "min_mult",
            "in": "query",
            "description": "Minimum volume multiple vs prior day",
            "schema": {
              "type": "number",
              "minimum": 1,
              "default": 2
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Movers (empty with a notice when adjacent daily snapshots are unavailable)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/v1/catalysts/upcoming": {
      "get": {
        "operationId": "listUpcomingCatalysts",
        "summary": "Scheduled catalysts (FOMC, CPI, earnings, elections…) in the next N days",
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 365,
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Dated catalyst calendar with source URLs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/v1/signals": {
      "get": {
        "operationId": "listSignals",
        "summary": "CM Signal wire index (analytics bulletins built on the reference layer)",
        "responses": {
          "200": {
            "description": "Wire index",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/v1/signals/{slug}": {
      "get": {
        "operationId": "getSignal",
        "summary": "One CM Signal bulletin",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bulletin JSON"
          },
          "404": {
            "description": "Unknown wire"
          }
        }
      }
    },
    "/v1/spot": {
      "get": {
        "operationId": "getSpot",
        "summary": "Reference spot prices (USD) for coins referenced by crypto markets",
        "responses": {
          "200": {
            "description": "Spot table with as-of timestamps"
          }
        }
      }
    },
    "/v1/keys": {
      "post": {
        "operationId": "createKey",
        "summary": "Create a free API key (optional — anonymous access works; a key raises the daily limit)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Key issued; send as `Authorization: Bearer <key>` or `?key=`"
          },
          "400": {
            "description": "Invalid email"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Event": {
        "$id": "https://clearmarket.fyi/schema/events.json",
        "title": "ClearMarket Event",
        "description": "Canonical record of a prediction market question. One row per canonical tradable question; every event has one or more markets attached. The editorial layer that platforms don't ship. Thematic grouping across events is handled via tags, not a hierarchy. API response shape includes derived fields (venues_covered, current_primary_mark) computed at serve time from the normalized 4-table storage. API responses add serve-time fields beyond this canonical schema (_provenance, _notice, and per-endpoint extras).",
        "type": "object",
        "required": [
          "event_id",
          "slug",
          "question",
          "category",
          "published",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "event_id": {
            "type": "string",
            "pattern": "^CM-EVT-[0-9A-Z]{10}$",
            "description": "ClearMarket canonical event ID. Format: 'CM-EVT-' + 9-char vowel-free base36 + 1-char mod-10 check digit. Stable forever — never changes."
          },
          "slug": {
            "type": "string",
            "description": "Human-readable URL form. Can change; not a stable identifier."
          },
          "question": {
            "type": "string",
            "description": "ClearMarket-canonical normalized English question text."
          },
          "category": {
            "type": "string",
            "enum": [
              "economics",
              "financials",
              "crypto",
              "companies",
              "technology",
              "health",
              "politics",
              "geopolitics",
              "climate"
            ],
            "description": "Top-level institutional classification. 9-enum (matches classify.py CATEGORIES_IN)."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Cross-cutting filter tags (editorial + platform)."
          },
          "primary_market_id": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^CM-MKT-[0-9]{6}$",
            "description": "FK to markets.market_id. The market quoted as the event's headline price. Auto-computed nightly unless locked."
          },
          "primary_market_locked": {
            "type": "boolean",
            "default": false,
            "description": "Editorial override flag. If true, primary_market_id is not auto-recomputed."
          },
          "catalyst_dates": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "date",
                "label"
              ],
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "type": {
                  "type": "string",
                  "description": "Catalyst type: fomc / cpi / jobs / gdp / ppi / corporate_earnings / etc."
                },
                "label": {
                  "type": "string",
                  "description": "Human-readable catalyst label."
                },
                "source_url": {
                  "type": "string",
                  "description": "Deep link to the authoritative source for this date (provenance)."
                }
              },
              "additionalProperties": false
            },
            "description": "Scheduled real-world events that drive resolution or repricing, with provenance. Macro from FRED, FOMC from the Fed calendar, earnings from API Ninjas, ad-hoc from Exa."
          },
          "published": {
            "type": "boolean",
            "default": false,
            "description": "API gate. If false, event is internal-only and excluded from public API responses."
          },
          "editorial_notes": {
            "type": [
              "string",
              "null"
            ],
            "description": "Public-facing editorial context (why this event is grouped, source quality caveats, cross-platform observations). Surfaced in API responses — this is the editorial layer platforms don't ship."
          },
          "venue": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "kalshi",
              "polymarket",
              null
            ],
            "description": "Primary venue this event was ingested from. (Cross-venue coverage is surfaced via venues_covered at serve time.)"
          },
          "bundle_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "categorical",
              "date_ladder",
              "strike_ladder",
              "augmented_negrisk",
              "singleton",
              null
            ],
            "description": "Resolution-inheritance shape of the event's child markets (OCC class->series analog). Determines which resolution fields are event-level shared vs per-child native."
          },
          "resolution_reference": {
            "type": [
              "string",
              "null"
            ],
            "description": "Generic, subject-free event-level resolution ontology (the OCC class-level settlement rule): the data source, mechanism, and deadline that resolve ANY outcome in this event, inherited by all children. Never names a specific child's subject; per-child references are composed from this plus each child's group_item_title."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Row creation timestamp (TIMESTAMPTZ)."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update timestamp (TIMESTAMPTZ)."
          },
          "venues_covered": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "kalshi",
                "polymarket"
              ]
            },
            "description": "DERIVED AT API SERVE TIME. Distinct platform values across all markets linked to this event."
          },
          "current_primary_mark": {
            "type": [
              "object",
              "null"
            ],
            "description": "DERIVED AT API SERVE TIME. Latest marks row for the event's primary_market_id. Shape matches the marks schema response."
          },
          "field_provenance": {
            "type": "object",
            "description": "Per-field provenance. Keys are field names; values are objects with 'source' ('platform_api' / 'clearmarket_editorial' / 'derived') and optional metadata.",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "source": {
                  "type": "string",
                  "enum": [
                    "platform_api",
                    "clearmarket_editorial",
                    "clearmarket_editorial_fallback",
                    "derived",
                    "imputed",
                    "null_by_venue_limitation"
                  ]
                }
              }
            }
          }
        }
      },
      "Market": {
        "$id": "https://clearmarket.fyi/schema/markets.json",
        "title": "ClearMarket Market",
        "description": "One row per market per platform. Raw venue data + ClearMarket editorial fill on top. Auto-ingested daily from Kalshi and Polymarket public APIs. API response shape includes the derived field also_on (the same question on other venues), computed at serve time. Thematic grouping across events is handled via tags on the linked event, not via fields on markets. API responses add serve-time fields beyond this canonical schema (_provenance, _notice, and per-endpoint extras).",
        "type": "object",
        "required": [
          "market_id",
          "platform",
          "platform_market_id",
          "contract_type",
          "settlement_currency",
          "status",
          "first_seen_at",
          "last_updated_at"
        ],
        "properties": {
          "market_id": {
            "type": "string",
            "pattern": "^CM-MKT-[0-9]{6}$",
            "description": "ClearMarket canonical market ID. Format: 'CM-MKT-' + 6-digit zero-padded sequence. Stable forever — never changes."
          },
          "platform": {
            "type": "string",
            "enum": [
              "kalshi",
              "polymarket"
            ],
            "description": "Source venue."
          },
          "platform_market_id": {
            "type": "string",
            "description": "Venue's native ID. Kalshi ticker (e.g., 'KXFED-26APR-T3.25') or Polymarket conditionId."
          },
          "event_id": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^CM-EVT-[0-9A-Z]{10}$",
            "description": "FK to events.event_id. Nullable — editorial assignment. Market can exist without an event."
          },
          "platform_event_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Platform's own grouping identifier (informational). Kalshi event_ticker; Polymarket event slug."
          },
          "question_raw": {
            "type": [
              "string",
              "null"
            ],
            "description": "Platform's short headline question."
          },
          "description_raw": {
            "type": [
              "string",
              "null"
            ],
            "description": "Platform's long prose description."
          },
          "category_raw": {
            "type": [
              "string",
              "null"
            ],
            "description": "Platform's own category classification."
          },
          "contract_type": {
            "type": "string",
            "enum": [
              "binary",
              "scalar"
            ],
            "description": "Binary YES/NO or true-scalar payout. v0.1 only populates binary; scalar support v0.2+."
          },
          "settlement_currency": {
            "type": "string",
            "enum": [
              "USD",
              "USDC"
            ],
            "description": "USD (Kalshi) or USDC (Polymarket)."
          },
          "tick_size": {
            "type": [
              "number",
              "null"
            ],
            "description": "Minimum price increment."
          },
          "contract_multiplier": {
            "type": [
              "number",
              "null"
            ],
            "description": "Notional per contract. Usually 1.0 for binaries."
          },
          "underlying_reference": {
            "type": [
              "string",
              "null"
            ],
            "description": "Editorial: specific real-world data reference (e.g., 'BLS Series CUUR0000SA0', 'S&P 500 index close per S&P Dow Jones Indices', 'Credible news reporting — no specific feed'). For multi-outcome events this is COMPOSED per child from the event's generic resolution_reference + this market's group_item_title, so each child names its own subject and no sibling's identity leaks."
          },
          "group_item_title": {
            "type": [
              "string",
              "null"
            ],
            "description": "Per-child subject within a multi-outcome event (the OSI-symbol analog): the candidate, company, strike, or date this market resolves on ('María Corina Machado', 'Discord', '$2 trillion', 'June 2026'). Native from the venue; composes underlying_reference against the event-level resolution_reference."
          },
          "close_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When trading stops (TIMESTAMPTZ)."
          },
          "last_trading_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Last tradeable date. May differ from close_at."
          },
          "resolve_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Expected payout date."
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "closed",
              "resolved",
              "amended"
            ],
            "description": "Market lifecycle state."
          },
          "resolution_rules_raw": {
            "type": [
              "string",
              "null"
            ],
            "description": "Full rules text from platform. Source for the parsed resolution_triggers."
          },
          "resolution_triggers": {
            "type": [
              "object",
              "null"
            ],
            "description": "Parsed machine-readable resolution structure. Editorial.",
            "properties": {
              "triggers": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    },
                    "metric": {
                      "type": "string"
                    },
                    "threshold": {},
                    "source": {
                      "type": "string"
                    },
                    "deadline": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    }
                  }
                },
                "description": "Array of resolution trigger conditions."
              },
              "trigger_logic": {
                "type": "string",
                "enum": [
                  "AND",
                  "OR",
                  "SINGLE"
                ]
              },
              "exclusions": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "What explicitly does not count as resolution."
              },
              "resolution_risks": {
                "type": "string",
                "description": "Known edge cases or dispute scenarios."
              }
            }
          },
          "arbitration_model": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "uma_oracle",
              "kalshi_staff",
              "polymarket_staff",
              "platform_auto",
              "determinations_committee",
              "other",
              null
            ],
            "description": "Who arbitrates disputes. Stored column (not derived)."
          },
          "resolution_proposer": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "permissionless",
              "managed_whitelist",
              "platform_staff",
              "gov_agency",
              null
            ],
            "description": "Who can propose resolution outcomes. 'managed_whitelist' captures UMA MOOV2 (Aug 2025 — whitelist of 37 proposers)."
          },
          "resolution_source": {
            "type": [
              "string",
              "null"
            ],
            "description": "What data is cited. Editorial fill for Polymarket where API is blank or prose is vague ('consensus of credible reporting')."
          },
          "source_citation": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Link to the data source itself (not the arbiter's admin page)."
          },
          "resolution_source_list": {
            "type": [
              "array",
              "null"
            ],
            "description": "Full source set: every venue-listed source (provenance: platform_api) plus prose-named authorities surfaced by the commitment judgment (provenance: clearmarket_editorial). Added by the source-layer refactor 2026-07-03.",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "url": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "provenance": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "enum": [
                    "platform_api",
                    "clearmarket_editorial",
                    null
                  ]
                }
              }
            }
          },
          "source_commitment": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "named",
              "uncommitted",
              "none",
              null
            ],
            "description": "Top-level commitment class, stamped at enrichment from the LLM commitment judgment (rubric version recorded in field_provenance). committed_secondhand markets carry 'named' here — the venue DID commit; the quality deficiency is expressed by the subtype and the grade cap."
          },
          "source_commitment_subtype": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "named",
              "committed_secondhand",
              "uncommitted_illustrative",
              "uncommitted_placeholder",
              "none",
              null
            ],
            "description": "Full commitment taxonomy (vocabulary: /schema/source-commitment/v1). Feeds the grade ceiling: uncommitted_illustrative caps B; committed_secondhand, uncommitted_placeholder and none cap C."
          },
          "source_of_record": {
            "type": [
              "string",
              "null"
            ],
            "description": "The committed source's name, copied VERBATIM from the venue's text or source list (never minted by the model — the anti-hallucination gate discards untraceable names). The authority for named; the secondhand source for committed_secondhand; null when uncommitted."
          },
          "source_status": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "platform_named",
              "no_committed_source",
              "no_source_stated",
              "unknown",
              null
            ],
            "description": "THE stamped source judgment — pure function of the LLM commitment classification, stamped at enrichment. Every surface (API/MCP/web/.json/JSON-LD) reads this; none re-derives from raw field presence. Serve layers emit 'unknown' for pre-refactor rows with no stamp and no commitment; the stored value is never 'unknown'."
          },
          "source_mechanism": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "single_authority",
              "precedence",
              "quorum",
              null
            ],
            "description": "How multiple sources bind when commitment=named: one controlling authority, a stated precedence/fallback rule, or a quorum (N sources must agree). The CFTC-comment tie-break disclosure, structured."
          },
          "source_type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "gov_stat_agency",
              "central_bank",
              "regulated_data_vendor",
              "media_consensus",
              "court_filing",
              "issuer_announcement",
              "scheduled_event",
              "subjective",
              "other",
              null
            ],
            "description": "Objectivity classification of the data source."
          },
          "threshold": {
            "type": [
              "number",
              "null"
            ],
            "description": "Numeric resolution threshold (e.g. 150000 for 'Bitcoin reaches $150,000'). Typed top-level field for cross-venue matching; the verbose parse stays in resolution_triggers. Null for non-numeric (occurrence) markets."
          },
          "direction": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "above",
              "below",
              "reach",
              "between",
              "occurrence",
              null
            ],
            "description": "Polarity of the claim relative to the threshold. An ATTRIBUTE, not an event discriminator — 'above'/'below' at the same threshold/window/settlement_style are the SAME claim (complementary; comparison normalizes polarity before computing a spread)."
          },
          "settlement_style": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "touch",
              "terminal",
              "relative",
              "occurrence",
              null
            ],
            "description": "How the contract settles on the underlying: 'touch' (level ever reached in a window), 'terminal' (level at a single point in time), 'relative' (new high/low), 'occurrence' (a discrete event happens). Distinct from arbitration_model (who arbitrates). Part of the cross-venue event key."
          },
          "question_id": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^CMX-[0-9A-F]{10}$",
            "description": "Canonical question id. The normalized real-world question this market settles (subject + threshold + settlement_style, plus window for terminal). Markets sharing a question_id are the SAME question — across venues and across events within a venue. The stable join key CM Signal references. Null where the market has not been canonicalized. (Value prefix is CMX- for historical continuity; it is the ClearMarket question id.)"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Entity tags for search + cross-cutting retrieval (e.g. 'bitcoin', 'deutsche-bank'). Market-level (events also carry tags). v1 plain strings; later resolved to sameAs Wikidata QIDs."
          },
          "regulatory_class": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "DCM",
              "DeFi",
              "Other",
              null
            ],
            "description": "Regulatory class of the venue. DCM: CFTC-regulated Designated Contract Market. DeFi: token-vote-arbitrated decentralized protocol. Other: anything not in those two buckets (e.g., Manifold, Augur, Zeitgeist, prediction-market projects without CFTC registration or token-vote arbitration)."
          },
          "analyst_notes": {
            "type": [
              "string",
              "null"
            ],
            "description": "ClearMarket editorial note surfacing operational edge cases, dispute risks, or time-cutoff details for the market. v0.2: populated via per-venue fallback in render layer. v0.3+: populate via resolution_triggers.resolution_risks in enhance.py."
          },
          "contract_terms_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Kalshi PDF link to full contract terms. Kalshi-only."
          },
          "resolution_outcome": {
            "type": [
              "string",
              "null"
            ],
            "description": "Once resolved: 'YES', 'NO', or scalar value. Null until resolved."
          },
          "resolution_value": {
            "type": [
              "number",
              "null"
            ],
            "description": "For scalar markets: final numeric value. Null for binary."
          },
          "resolved_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Actual settlement timestamp."
          },
          "first_seen_at": {
            "type": "string",
            "format": "date-time",
            "description": "When ClearMarket first ingested this market."
          },
          "last_updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Most recent ingestion update."
          },
          "also_on": {
            "type": [
              "array",
              "null"
            ],
            "description": "DERIVED. The SAME question (same question_id) priced on other venues. Non-null only when this market's question_id has markets on a different venue; null when the question is unique to this venue. Lets a consumer see the cross-venue twin(s) without a second lookup.",
            "items": {
              "type": "object",
              "properties": {
                "venue": {
                  "type": "string",
                  "enum": [
                    "kalshi",
                    "polymarket"
                  ],
                  "description": "The other venue this question trades on."
                },
                "market_id": {
                  "type": "string",
                  "description": "FK to the counterpart market (market_id) on that venue."
                },
                "price": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "description": "Last price (implied probability) of the counterpart market."
                }
              },
              "required": [
                "venue",
                "market_id"
              ],
              "additionalProperties": false
            }
          },
          "field_provenance": {
            "type": "object",
            "description": "Per-field provenance. Keys are field names; values indicate 'platform_api' / 'clearmarket_editorial' / 'derived' / 'null_by_venue_limitation'.",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "source": {
                  "type": "string",
                  "enum": [
                    "platform_api",
                    "clearmarket_editorial",
                    "clearmarket_editorial_fallback",
                    "composed:event+child",
                    "inherited:event",
                    "native:expiration_time",
                    "derived:group_item_title",
                    "derived",
                    "imputed",
                    "null_by_venue_limitation"
                  ]
                }
              }
            }
          }
        }
      },
      "Mark": {
        "$id": "https://clearmarket.fyi/schema/marks.json",
        "title": "ClearMarket Mark",
        "description": "Daily pricing and liquidity snapshot. One row per market per UTC date. Normalizes Kalshi + Polymarket into a single feed with consistent field names and units (USD). Populated via GitHub Actions daily cron against platform public APIs. v0.1 includes Polymarket CLOB calls to populate size and no-side fields. API responses add serve-time fields beyond this canonical schema (_provenance, _notice, and per-endpoint extras).",
        "type": "object",
        "required": [
          "mark_id",
          "market_id",
          "snapshot_date",
          "snapshot_at",
          "source_updated_at",
          "mark_method",
          "stale_flag",
          "source_count"
        ],
        "properties": {
          "mark_id": {
            "type": "integer",
            "description": "BIGSERIAL auto-generated primary key."
          },
          "market_id": {
            "type": "string",
            "pattern": "^CM-MKT-[0-9]{6}$",
            "description": "FK to markets.market_id."
          },
          "snapshot_date": {
            "type": "string",
            "format": "date",
            "description": "UTC calendar date of the snapshot. Unique with market_id (one mark per market per day)."
          },
          "snapshot_at": {
            "type": "string",
            "format": "date-time",
            "description": "Exact moment of API pull (TIMESTAMPTZ). Distinct from snapshot_date."
          },
          "source_updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Venue's own 'last updated' timestamp (Kalshi updated_time, Polymarket updatedAt). Compare to snapshot_at for staleness."
          },
          "yes_bid": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1,
            "description": "Best bid price on the yes-side book. Decimal 0-1."
          },
          "yes_ask": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1,
            "description": "Best ask price on the yes-side book. Decimal 0-1."
          },
          "no_bid": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1,
            "description": "Best bid price on the no-side book. For Polymarket, populated via CLOB API call."
          },
          "no_ask": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1,
            "description": "Best ask price on the no-side book. For Polymarket, populated via CLOB API call."
          },
          "yes_bid_size_usd": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "description": "USD-normalized size at best yes-bid. Computed as contracts * price. TOP-OF-BOOK ONLY, not full-book depth."
          },
          "yes_ask_size_usd": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "description": "USD-normalized size at best yes-ask. TOP-OF-BOOK ONLY."
          },
          "no_bid_size_usd": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "description": "USD-normalized size at best no-bid. TOP-OF-BOOK ONLY."
          },
          "no_ask_size_usd": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "description": "USD-normalized size at best no-ask. TOP-OF-BOOK ONLY."
          },
          "yes_last_price": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1,
            "description": "Last traded price on the yes-side. Decimal 0-1."
          },
          "implied_probability": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 1,
            "description": "For binary markets: equals yes_last_price. For scalar strike ladders: normalized probability mass across the ladder (computed at serve time)."
          },
          "volume_24h_usd": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "description": "Dollar trading volume in the last 24 hours. Kalshi value is imputed (contracts * last_price); Polymarket value is native USDC."
          },
          "volume_total_usd": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "description": "Cumulative dollar trading volume since market opened. Kalshi value is imputed; Polymarket native."
          },
          "open_interest_usd": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "description": "Dollar value of positions currently held. Kalshi-native; NULL for Polymarket (not exposed without on-chain subgraph — v0.2+)."
          },
          "mark_method": {
            "type": "string",
            "enum": [
              "venue_snapshot",
              "imputed_carry_forward",
              "editorial_override"
            ],
            "description": "How this mark was produced. 'venue_snapshot' = pulled directly from API (default). 'imputed_carry_forward' = prior day carried forward when venue returned no data. 'editorial_override' = manual correction (rare)."
          },
          "stale_flag": {
            "type": "boolean",
            "description": "True if hours_since_source_update > STALENESS_THRESHOLD_HOURS (4). Warns consumer that the venue data itself is older than our freshness commitment."
          },
          "source_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Number of distinct API responses feeding this mark. 1 in v0.1. Reserved for future blended quotes."
          },
          "raw_payload": {
            "type": [
              "object",
              "null"
            ],
            "description": "Full raw API response(s) for audit. Preserves all venue-native fields not surfaced as first-class columns (contracts counts, umaBond, rewardsMaxSpread, fractional_trading_enabled, etc.)."
          },
          "spread": {
            "type": [
              "number",
              "null"
            ],
            "description": "DERIVED AT API SERVE TIME. Computed as yes_ask - yes_bid."
          },
          "mid": {
            "type": [
              "number",
              "null"
            ],
            "description": "DERIVED AT API SERVE TIME. Computed as (yes_bid + yes_ask) / 2."
          },
          "divergence_from_primary": {
            "type": [
              "number",
              "null"
            ],
            "description": "DERIVED AT API SERVE TIME. abs(yes_last_price - this event's primary market's yes_last_price). Null when event has one market or no primary_market_id set."
          },
          "hours_since_source_update": {
            "type": [
              "number",
              "null"
            ],
            "description": "DERIVED AT API SERVE TIME. (snapshot_at - source_updated_at) in hours. Used to compute stale_flag."
          },
          "field_provenance": {
            "type": "object",
            "description": "Per-field provenance. Keys are field names; values indicate 'platform_api' / 'derived' / 'imputed' / 'null_by_venue_limitation'.",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "source": {
                  "type": "string",
                  "enum": [
                    "platform_api",
                    "derived",
                    "imputed",
                    "null_by_venue_limitation",
                    "clearmarket_editorial"
                  ]
                }
              }
            }
          }
        }
      },
      "ResolutionLogEntry": {
        "$id": "https://clearmarket.fyi/schema/resolution_log.json",
        "title": "ClearMarket Resolution Log Entry",
        "description": "Append-only audit trail of lifecycle events for a market. Never updated, never deleted. Row sequence reconstructs the market's full history. v0.1 populates status_change / rule_change / resolved events via platform API diffing. resolution_proposed and disputed events require UMA subgraph reader (v0.3+). amended and reversed events require editorial observation. API responses add serve-time fields beyond this canonical schema (_provenance, _notice, and per-endpoint extras).",
        "type": "object",
        "required": [
          "log_id",
          "market_id",
          "event_type",
          "occurred_at",
          "recorded_at",
          "source"
        ],
        "properties": {
          "log_id": {
            "type": "integer",
            "description": "BIGSERIAL auto-generated primary key."
          },
          "market_id": {
            "type": "string",
            "pattern": "^CM-MKT-[0-9]{6}$",
            "description": "FK to markets.market_id."
          },
          "event_type": {
            "type": "string",
            "enum": [
              "status_change",
              "rule_change",
              "resolution_proposed",
              "disputed",
              "resolved",
              "amended",
              "reversed"
            ],
            "description": "Lifecycle event type. status_change: market state transition (active -> closed, etc). rule_change: resolution criteria amended mid-life. resolution_proposed: outcome submitted (UMA or staff). disputed: proposed resolution challenged. resolved: final outcome committed. amended: post-resolution correction. reversed: post-resolution full reversal."
          },
          "occurred_basis": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "venue_settlement",
              "deadline",
              "first_observed",
              null
            ],
            "description": "Which clock occurred_at holds. venue_settlement: the venue's actual settlement timestamp (Kalshi settlement_ts, Polymarket closedTime). deadline: the contract deadline, used as fallback when the venue exposes no settlement time (e.g. delisted before settlement) — deadline-basis timestamps are NOT settlement times. first_observed: neither was available; the first pipeline observation date."
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the event happened, by the venue's clock. Authoritative event timestamp."
          },
          "recorded_at": {
            "type": "string",
            "format": "date-time",
            "description": "When ClearMarket captured this event. Gap between occurred_at and recorded_at = detection lag."
          },
          "from_value": {
            "type": [
              "string",
              "null"
            ],
            "description": "Prior state. For status_change: old status string. For rule_change: snippet of old rule. NULL for initial creation events."
          },
          "to_value": {
            "type": [
              "string",
              "null"
            ],
            "description": "New state. Same format as from_value."
          },
          "diff": {
            "type": [
              "object",
              "null"
            ],
            "description": "Structured diff for multi-field changes (rule_change, complex amended). Simple status changes leave this null. Free-form JSONB — typical shape: {field_name: {before, after}, reason_prose}."
          },
          "source": {
            "type": "string",
            "enum": [
              "platform_api",
              "uma_subgraph",
              "editorial_observation",
              "platform_announcement",
              "cftc_filing"
            ],
            "description": "How ClearMarket detected this event. v0.1 supports platform_api, editorial_observation, platform_announcement. uma_subgraph and cftc_filing are v0.3+."
          },
          "source_ref": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pointer into the source: UMA dispute ID (for uma_subgraph), announcement URL (platform_announcement), editorial commit hash (editorial_observation). Null for platform_api events."
          },
          "actor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Who caused the event: platform name, UMA proposer address, editorial author. NULL for autonomous platform state transitions where actor is implicit."
          }
        }
      }
    }
  }
}