openapi: 3.1.0
info:
  title: Orrery Probability Intelligence API (x402)
  version: 1.0.0
  description: |
    Paid per-call intelligence layer over public prediction-market data.

    Built for autonomous AI agents discovering services on Agentic Market.
    Paid calls can use an Orrery API key tied to a monthly credit pack
    (`X-Orrery-API-Key`) or stay account-less and stateless via the x402
    protocol (`HTTP 402` + on-chain USDC settlement on Base). Per-call
    pricing is still quoted in the response challenge.

    All responses use the same envelope (`schema_version: orrery.envelope.v1`):
      {
        "data": {
          "schema_version": "orrery.<endpoint>.v1",
          ...endpoint-specific payload...
        },
        "meta": {
          "schema_version": "orrery.envelope.v1",
          "endpoint": "/api/x402/v1/...",
          "fetched_at": "ISO-8601",
          "snapshot_id": "snap_YYYY-MM-DDTHH-mmZ",
          "cache_seconds": 120,
          "payment_status": "preview" | "settled" | "missing" | "rate_limited",
          "usdc_per_call": 0.005,
          "sources": ["Polymarket Gamma", "Kalshi public Trade API"],
          "not_trade_advice": true
        }
      }

    Two parallel version streams:
      • `meta.schema_version` versions the envelope itself; bump
        signals a breaking change to meta.
      • `data.schema_version` versions the inner payload per endpoint
        (e.g. `orrery.health.v1`, `orrery.brief.today.v1`).
    Agents pinning either should assert the exact value and fall back
    to vendor docs on mismatch. The same value is also returned in
    the `X-Orrery-Schema-Version` HTTP header.

    Production paid endpoints require either an Orrery API key with monthly
    credits or x402 settlement. Callers without a valid `X-Orrery-API-Key`
    or `X-PAYMENT` header receive HTTP 402 with a JSON challenge listing
    the price, network, asset, and payTo address. Verified settlement or
    successful credit consumption returns `payment_status: "settled"`;
    throttled calls are represented as `payment_status: "rate_limited"`
    where an envelope is emitted. Free public endpoints such as
    /api/x402/v1/health remain tagged `payment_status: "preview"` with
    zero price.

    Discovery files:
      • Public llms.txt:        https://orrery.me/llms.txt
      • Agent plugin manifest:  https://orrery.me/.well-known/ai-plugin.json
      • x402 service catalog:   https://orrery.me/.well-known/x402-services.json
  contact:
    name: Orrery
    email: hello@orrery.me
    url: https://orrery.me/contact
  license:
    name: Public read-only data — see https://orrery.me/terms
servers:
  - url: https://orrery.me
    description: Production (x402 payment enforced)
x-orrery-pricing:
  description: |
    Per-call USDC pricing for every paid endpoint, locked in
    /.well-known/x402-services.json. Listed here for convenience and
    so OpenAPI tooling can lint each path against its catalog price.
    Free endpoints (e.g. /health) are omitted from this table.
  prices:
    - { endpoint: "/api/x402/v1/decision/attention",          usdc_per_call: 0.05 }
    - { endpoint: "/api/x402/v1/decision/market/{id}",        usdc_per_call: 0.15 }
    - { endpoint: "/api/x402/v1/brief/today",                 usdc_per_call: 0.01 }
    - { endpoint: "/api/x402/v1/markets/movers",              usdc_per_call: 0.005 }
    - { endpoint: "/api/x402/v1/markets",                     usdc_per_call: 0.005 }
    - { endpoint: "/api/x402/v1/divergence/top",              usdc_per_call: 0.05 }
    - { endpoint: "/api/x402/v1/markets/{id}/snapshot",       usdc_per_call: 0.005 }
    - { endpoint: "/api/x402/v1/markets/{id}/why",            usdc_per_call: 0.02 }
    - { endpoint: "/api/x402/v1/markets/{id}/resolution-risk", usdc_per_call: 0.01 }
    - { endpoint: "/api/x402/v1/events/{slug}/cluster",       usdc_per_call: 0.03 }
    - { endpoint: "/api/x402/v1/signals",                     usdc_per_call: 0.01 }
    - { endpoint: "/api/x402/v1/watchlist/summary",           usdc_per_call: 0.05 }
    - { endpoint: "/api/x402/v1/portfolio/risk",              usdc_per_call: 0.05 }
    - { endpoint: "/api/x402/v1/share-card/{slug}",           usdc_per_call: 0.03 }
    - { endpoint: "/api/x402/v1/wallets/{address}",           usdc_per_call: 0.02 }
    - { endpoint: "/api/x402/v1/category/{slug}/intelligence", usdc_per_call: 0.02 }
    - { endpoint: "/api/x402/v1/backtest/{kind}",             usdc_per_call: 0.02 }
    - { endpoint: "/api/x402/v1/search",                      usdc_per_call: 0.005 }
    - { endpoint: "/api/x402/v1/events",                      usdc_per_call: 0.005 }
    - { endpoint: "/api/x402/v1/signals/{kind}",              usdc_per_call: 0.01 }
    - { endpoint: "/api/x402/v1/trades/recent",               usdc_per_call: 0.005 }
tags:
  - name: brief
    description: Daily prediction-market brief
  - name: markets
    description: Per-market intelligence
  - name: venues
    description: Multi-venue market normalization
  - name: events
    description: Event clusters
  - name: signals
    description: Live signal feed
  - name: portfolio
    description: Portfolio + watchlist intelligence
components:
  securitySchemes:
    x402:
      type: apiKey
      in: header
      name: X-PAYMENT
      description: |
        On-chain settlement proof for x402 payment. Paid endpoints return
        HTTP 402 with a JSON challenge when this header is missing or invalid.
    orreryApiKey:
      type: apiKey
      in: header
      name: X-Orrery-API-Key
      description: |
        Orrery API key tied to a monthly credit pack. The server consumes
        monthly credits first; if credits are unavailable or exhausted,
        callers can still fall back to the x402 challenge flow.
  schemas:
    EnvelopeMeta:
      type: object
      required: [endpoint, fetched_at, cache_seconds, payment_status, usdc_per_call, sources, not_trade_advice]
      properties:
        endpoint: { type: string }
        fetched_at: { type: string, format: date-time }
        cache_seconds: { type: integer }
        payment_status:
          type: string
          enum: [preview, settled, missing, rate_limited]
        usdc_per_call: { type: number, format: float }
        sources:
          type: array
          items: { type: string }
        not_trade_advice:
          type: boolean
          enum: [true]
    PaymentChallenge:
      type: object
      properties:
        error:
          type: string
          enum: [payment_required]
        accepts:
          type: array
          items:
            type: object
            properties:
              scheme: { type: string, example: exact }
              network: { type: string, example: eip155:8453 }
              asset: { type: string, example: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" }
              amount: { type: string, example: "10000" }
              payTo: { type: string, example: "0x0000000000000000000000000000000000000000" }
        description: { type: string }
        docs: { type: string }
    DecisionScores:
      type: object
      required: [attention, confidence, risk]
      properties:
        attention:
          type: number
          format: float
          minimum: 0
          maximum: 100
          description: Composite urgency 0..100. >70 indicates investigate_now territory.
        confidence:
          type: number
          format: float
          minimum: 0
          maximum: 1
          description: How sure Orrery is about the read.
        risk:
          type: number
          format: float
          minimum: 0
          maximum: 1
          description: Danger of acting on this without verification.
    DecisionEvidence:
      type: object
      required: [type, summary, observed_at, weight, data]
      properties:
        type:
          type: string
          enum: [price_move, volume_pressure, liquidity, whale_activity, signal_evidence, resolution_proximity, uma_state, source_type, smart_money_flow, freshness, novelty]
        observed_at: { type: string, format: date-time }
        summary: { type: string }
        weight:
          type: number
          format: float
          minimum: 0
          maximum: 1
        data:
          type: object
          additionalProperties: true
    DecisionRisk:
      type: object
      required: [type, severity, summary]
      properties:
        type:
          type: string
          enum: [resolution_ambiguity, uma_dispute, liquidity, source_conflict, manipulation, settlement_positioning, stale_data]
        severity:
          type: string
          enum: [low, medium, high]
        summary: { type: string }
    DecisionSource:
      type: object
      required: [source_type, name, observed_at]
      properties:
        source_type:
          type: string
          enum: [market, onchain, uma_oracle, news, exchange_price, official_government, company_filing, orrery]
        name: { type: string }
        url: { type: string, format: uri }
        observed_at: { type: string, format: date-time }
    SuggestedNextCall:
      type: object
      required: [endpoint, method, reason, estimated_price_usdc, priority]
      properties:
        endpoint: { type: string, example: /api/x402/v1/markets/{id}/why }
        method: { type: string, enum: [GET, POST] }
        reason: { type: string }
        estimated_price_usdc: { type: number, format: float, example: 0.02 }
        priority: { type: string, enum: [low, medium, high] }
    DecisionCard:
      type: object
      required:
        - schema_version
        - decision_type
        - generated_at
        - valid_until
        - recommended_agent_action
        - scores
        - one_line_reason
        - why_this_matters
        - evidence
        - risks
        - sources
        - suggested_next_calls
        - payload
        - disclaimer
      properties:
        schema_version: { type: string, enum: [orrery.decision.v1] }
        decision_type:
          type: string
          enum: [attention_queue, market_decision, move_explanation, resolution_risk, agent_brief, wallet_intelligence, category_intelligence, event_cluster, signal_feed]
        generated_at: { type: string, format: date-time }
        valid_until:
          type: string
          format: date-time
          description: Freshness budget — agent should re-fetch after this.
        market_id: { type: string }
        recommended_agent_action:
          type: string
          enum: [ignore, monitor, investigate_now, deep_research, check_resolution_risk, check_liquidity, check_sources, alert_human]
        scores: { $ref: '#/components/schemas/DecisionScores' }
        one_line_reason:
          type: string
          description: One sentence the agent can quote verbatim.
        why_this_matters:
          type: array
          items: { type: string }
        evidence:
          type: array
          items: { $ref: '#/components/schemas/DecisionEvidence' }
        risks:
          type: array
          items: { $ref: '#/components/schemas/DecisionRisk' }
        sources:
          type: array
          items: { $ref: '#/components/schemas/DecisionSource' }
        suggested_next_calls:
          type: array
          items: { $ref: '#/components/schemas/SuggestedNextCall' }
        payload:
          type: object
          description: Endpoint-specific payload — see the per-endpoint schema.
          additionalProperties: true
        disclaimer:
          type: string
          example: "Decision-support data only. Not financial, trading, legal, tax, or betting advice."
    AttentionItem:
      type: object
      required: [rank, market_id, market_url, question, category, recommended_agent_action, scores, freshness_seconds, one_line_reason, top_risks, suggested_next_calls]
      properties:
        rank: { type: integer, minimum: 1 }
        market_id: { type: string }
        market_url: { type: string, format: uri }
        question: { type: string }
        category: { type: string }
        recommended_agent_action: { $ref: '#/components/schemas/DecisionCard/properties/recommended_agent_action' }
        scores: { $ref: '#/components/schemas/DecisionScores' }
        freshness_seconds: { type: integer }
        one_line_reason: { type: string }
        top_risks:
          type: array
          items: { type: string }
        suggested_next_calls:
          type: array
          items: { $ref: '#/components/schemas/SuggestedNextCall' }
paths:
  /api/v1/manifest:
    get:
      tags: [discovery, free]
      summary: Free machine-readable index of the Decision API.
      description: |
        The free index of every paid endpoint with prices, schemas,
        decision types, revenue ladders, and example URLs. No payment.
      responses:
        '200':
          description: Manifest object.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
  /api/x402/v1/decision/market/{id}:
    get:
      tags: [decision-api, flagship]
      summary: Single-market deep-dive Decision Card (aggregate)
      description: |
        Use when your agent has identified a specific market and wants
        snapshot + move-explanation + resolution-risk + 7-day price-
        history summary + top YES/NO holders + related markets in one
        round-trip. This is the premium aggregate path: it costs more
        than the base snapshot + why + resolution-risk fan-out, but
        includes holder data, related markets, and one stable Decision
        Card for latency-budgeted agents.
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
          description: Polymarket market slug.
      responses:
        '200':
          description: Decision Card with market_decision payload.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data: { $ref: '#/components/schemas/DecisionCard' }
                  meta: { $ref: '#/components/schemas/EnvelopeMeta' }
        '402':
          description: Payment required.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/PaymentChallenge' }
        '404':
          description: Market not found.
  /api/x402/v1/decision/attention:
    get:
      tags: [decision-api, flagship]
      summary: Attention Queue — flagship Decision API endpoint
      description: |
        Use this endpoint when your agent needs to decide which prediction
        markets deserve immediate investigation right now. Returns ranked
        Decision Cards with composite attention/confidence/risk scores,
        top risks per market, and suggested_next_calls pointing at the
        deep dives.
      parameters:
        - { name: category, in: query, schema: { type: string, enum: [all, crypto, macro, politics, geopolitics, sports, tech, ai], default: all } }
        - { name: limit, in: query, schema: { type: integer, minimum: 1, maximum: 25, default: 10 } }
        - { name: risk_tolerance, in: query, schema: { type: string, enum: [low, medium, high], default: medium } }
        - { name: max_age_minutes, in: query, schema: { type: integer, minimum: 1, maximum: 1440, default: 60 } }
      responses:
        '200':
          description: Decision Card with attention_queue payload.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    allOf:
                      - $ref: '#/components/schemas/DecisionCard'
                      - properties:
                          payload:
                            type: object
                            properties:
                              query:
                                type: object
                                properties:
                                  category: { type: string, nullable: true }
                                  limit: { type: integer }
                                  risk_tolerance: { type: string }
                                  max_age_minutes: { type: integer }
                              summary:
                                type: object
                                properties:
                                  total_markets_scanned: { type: integer }
                                  signals_considered: { type: integer }
                                  items_returned: { type: integer }
                              items:
                                type: array
                                items: { $ref: '#/components/schemas/AttentionItem' }
                  meta: { $ref: '#/components/schemas/EnvelopeMeta' }
        '402':
          description: Payment required (when X402_PAYMENTS_ENFORCED=true).
          content:
            application/json:
              schema: { $ref: '#/components/schemas/PaymentChallenge' }
  /api/x402/v1/brief/today:
    get:
      tags: [brief]
      summary: Today's machine-readable daily brief
      description: |
        Compact JSON edition of the public Daily Brief: biggest moves,
        unusual volume, research signals, resolution watch, smart-money
        flow, headline, and next-action hints pointing at sister
        endpoints. Cache 5 min.
      security:
        - orreryApiKey: []
        - x402: []
      responses:
        '200':
          description: OK — brief envelope
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      date: { type: string, example: "2026-04-30" }
                      headline: { type: string }
                      biggest_moves: { type: array, items: { type: object } }
                      unusual_volume: { type: array, items: { type: object } }
                      research_signals: { type: array, items: { type: object } }
                      resolution_watch: { type: array, items: { type: object } }
                      smart_money_flow: { type: array, items: { type: object } }
                      next_actions: { type: array, items: { type: string } }
                  meta:
                    $ref: '#/components/schemas/EnvelopeMeta'
        '402':
          description: Payment required — agent must settle on-chain and replay
          content:
            application/json:
              schema: { $ref: '#/components/schemas/PaymentChallenge' }
        '429':
          description: Rate-limited (60 req/min/IP)
  /api/x402/v1/markets/movers:
    get:
      tags: [markets]
      summary: Biggest 24h probability movers
      description: Ranked by absolute 24h delta, filtered to live markets only.
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: query
          name: limit
          schema: { type: integer, default: 10, maximum: 50 }
        - in: query
          name: category
          schema: { type: string }
          description: Case-insensitive category match (e.g. "Crypto").
        - in: query
          name: min_liquidity
          schema: { type: number, default: 5000 }
        - in: query
          name: direction
          schema: { type: string, enum: [up, down] }
      responses:
        '200': { description: OK — movers envelope }
        '402': { description: Payment required }
        '429': { description: Rate-limited }
  /api/x402/v1/venues:
    get:
      tags: [venues]
      summary: Free venue catalog
      description: |
        Lists Orrery's supported data venues and the read-only posture for
        each connector. Use this before calling multi-venue endpoints.
      responses:
        '200': { description: OK — venue catalog envelope }
  /api/x402/v1/markets:
    get:
      tags: [venues, markets]
      summary: Normalized market list by venue
      description: |
        Returns canonical market objects for a single venue while preserving
        venue-specific status, settlement rules, source status, and URLs.
        Supported values: `venue=polymarket` and `venue=kalshi`.
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: query
          name: venue
          schema: { type: string, enum: [polymarket, kalshi], default: polymarket }
        - in: query
          name: limit
          schema: { type: integer, default: 50, maximum: 200 }
        - in: query
          name: q
          schema: { type: string }
          description: Optional title search.
      responses:
        '200': { description: OK — canonical markets envelope }
        '402': { description: Payment required }
  /api/x402/v1/divergence/top:
    get:
      tags: [venues, markets]
      summary: Top cross-venue probability gaps
      description: |
        Compares the top Polymarket and Kalshi universes with a conservative
        same-event matcher. `exact` matches are probability-comparable. `near`
        and `related` matches carry warnings and should not be used as direct
        odds-arbitrage without reading both contract rules.
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: query
          name: limit
          schema: { type: integer, default: 20, maximum: 50 }
        - in: query
          name: universe
          schema: { type: integer, default: 120, maximum: 200 }
        - in: query
          name: include_related
          schema: { type: boolean, default: false }
          description: Include related-only theme matches when `match=all`.
        - in: query
          name: match
          schema: { type: string, enum: [all, exact, near, related], default: all }
          description: Filter by match quality. Only exact rows are probability-comparable.
        - in: query
          name: min_gap_pp
          schema: { type: number, default: 0, minimum: 0, maximum: 100 }
          description: Minimum absolute probability gap in percentage points.
        - in: query
          name: category
          schema: { type: string }
          description: Case-insensitive category or category slug filter.
        - in: query
          name: q
          schema: { type: string }
          description: Optional title, subtitle, or venue ticker search.
      responses:
        '200': { description: OK — cross-venue divergence envelope }
        '402': { description: Payment required }
  /api/x402/v1/markets/{id}/snapshot:
    get:
      tags: [markets]
      summary: Compact per-market snapshot
      description: |
        Probability, deltas, volume, status, resolution source, active
        signals, related markets, in one payload.
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: string }
          description: Polymarket slug (e.g. "btc-above-100k").
      responses:
        '200': { description: OK — snapshot envelope }
        '402': { description: Payment required }
        '404': { description: Market not found }
  /api/x402/v1/markets/{id}/why:
    get:
      tags: [markets]
      summary: Why did this market move? — interpreted explanation
      description: |
        Returns a list of factors with structured evidence + per-factor
        confidence, plus a what-to-verify checklist. Deterministic — no
        LLM call. Same logic as the in-app "Why did it move?" panel.
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: string }
      responses:
        '200': { description: OK — why envelope }
        '402': { description: Payment required }
        '404': { description: Market not found }
  /api/x402/v1/markets/{id}/resolution-risk:
    get:
      tags: [markets]
      summary: Resolution-risk analysis
      description: |
        Source extraction + UMA dispute status + ambiguity hints +
        what-to-verify list. The single most important call before
        treating any market move as news.
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: string }
      responses:
        '200': { description: OK — resolution-risk envelope }
        '402': { description: Payment required }
        '404': { description: Market not found }
  /api/x402/v1/events/{slug}/cluster:
    get:
      tags: [events]
      summary: All markets around one event
      description: |
        Aggregates every market under a Polymarket event: cluster volume,
        average move, top movers, resolution risks, and a one-line summary.
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: path
          name: slug
          required: true
          schema: { type: string }
      responses:
        '200': { description: OK — event cluster envelope }
        '402': { description: Payment required }
        '404': { description: Event not found }
  /api/x402/v1/signals:
    get:
      tags: [signals]
      summary: Live signal feed across top markets
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: query
          name: limit
          schema: { type: integer, default: 20, maximum: 60 }
        - in: query
          name: kind
          schema: { type: string }
          description: Comma-separated. Allowed — flow,momentum,divergence,resolution_risk
        - in: query
          name: min_evidence
          schema: { type: string, enum: [low, medium, high] }
        - in: query
          name: category
          schema: { type: string }
      responses:
        '200': { description: OK — signals envelope (returns empty array when no signals match the filter — this endpoint never 404s) }
        '402': { description: Payment required }
        '429': { description: Rate-limited (60 req/min/IP) }
  /api/x402/v1/watchlist/summary:
    post:
      tags: [portfolio]
      summary: Compose intelligence over a custom watchlist
      description: |
        Pass a set of slugs, themes (category slugs), and wallet
        addresses; receive movers, signals, resolution changes, whale
        flow, and a priority-scored items list back.
      security:
        - orreryApiKey: []
        - x402: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                markets:
                  type: array
                  items: { type: string }
                  maxItems: 50
                themes:
                  type: array
                  items: { type: string }
                  maxItems: 10
                wallets:
                  type: array
                  items: { type: string, pattern: '^0x[a-fA-F0-9]{40}$' }
                  maxItems: 10
      responses:
        '200': { description: OK — watchlist summary envelope }
        '402': { description: Payment required }
        '400': { description: Empty or invalid request }
  /api/x402/v1/portfolio/risk:
    post:
      tags: [portfolio]
      summary: Portfolio-risk cockpit for one or more wallets
      description: |
        Read-only aggregation across Polymarket addresses: open
        notional, unrealized PnL, largest positions, upcoming
        resolutions, single-position concentration, stale-pricing
        exposure. No wallet signatures.
      security:
        - orreryApiKey: []
        - x402: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [addresses]
              properties:
                addresses:
                  type: array
                  items: { type: string, pattern: '^0x[a-fA-F0-9]{40}$' }
                  minItems: 1
                  maxItems: 10
      responses:
        '200': { description: OK — portfolio risk envelope }
        '402': { description: Payment required }
        '400': { description: Empty or invalid request }
  /api/x402/v1/share-card/{slug}:
    get:
      tags: [markets]
      summary: Pre-formatted share artefact for a market move
      description: |
        Returns the OG image URL plus ready-to-publish copy variants
        for X (single post + thread), Telegram, Discord, and
        newsletter. Generated deterministically from the live
        market state — no LLM call.
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: path
          name: slug
          required: true
          schema: { type: string }
      responses:
        '200': { description: OK — share-card envelope }
        '402': { description: Payment required }
        '404': { description: Market not found }
  /api/x402/v1/wallets/{address}:
    get:
      tags: [portfolio]
      summary: Per-wallet intelligence with dimensional scoring
      description: |
        Open notional, PnL, win rate, top category, plus the five
        independent dimensions: activity / performance confidence /
        specialization / early-entry / copy-risk. Same scoring
        engine as the in-app /wallets/{address} surface.
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: path
          name: address
          required: true
          schema: { type: string, pattern: '^0x[a-fA-F0-9]{40}$' }
      responses:
        '200': { description: OK — wallet intelligence envelope }
        '402': { description: Payment required }
        '400': { description: Invalid address }
  /api/x402/v1/category/{slug}/intelligence:
    get:
      tags: [markets]
      summary: Category-level intelligence dashboard
      description: |
        Aggregate metrics for one category slug: total volume, avg
        volatility, top movers count, source-risk count, whale
        flow USD, resolving-soon count, and a one-line summary.
        Known slugs — crypto, ai, politics, geopolitics, macro,
        sports, tech, entertainment, science, business, weather.
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: path
          name: slug
          required: true
          schema: { type: string }
      responses:
        '200': { description: OK — category intelligence envelope }
        '402': { description: Payment required }
        '404': { description: Unknown category slug }
  /api/x402/v1/backtest/{kind}:
    get:
      tags: [signals]
      summary: Backtest verdict for one signal kind
      description: |
        Live backtest run over the top-15 highest-volume markets
        for `momentum` and `divergence`. For `flow`,
        `resolution_risk`, and `news_lag`, returns a
        `forward-only` verdict with the documented reason — no
        fabricated numbers.
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: path
          name: kind
          required: true
          schema:
            type: string
            enum: [momentum, divergence, flow, resolution_risk, news_lag]
      responses:
        '200': { description: OK — backtest envelope }
        '402': { description: Payment required }
        '404': { description: Unknown signal kind }
  /api/x402/v1/search:
    get:
      tags: [markets]
      summary: Free-text market search
      description: |
        Find a Polymarket market by free-text query. Useful as the
        first call when an agent has the user's prose ("Bitcoin
        $100k") but not the slug. Same algorithm as the in-app
        command palette — agents and humans get identical results.
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: query
          name: q
          required: true
          schema: { type: string, minLength: 1, maxLength: 200 }
        - in: query
          name: limit
          schema: { type: integer, default: 10, maximum: 20 }
        - in: query
          name: category
          schema: { type: string }
      responses:
        '200': { description: OK — search envelope }
        '402': { description: Payment required }
        '400': { description: Missing or invalid query }
  /api/x402/v1/events:
    get:
      tags: [events]
      summary: Top events by 24h volume
      description: |
        Discover event slugs to fan out to
        `/api/x402/v1/events/{slug}/cluster`. The first call an
        agent should make when it doesn't yet know which events
        are alive.
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: query
          name: limit
          schema: { type: integer, default: 20, maximum: 50 }
        - in: query
          name: category
          schema: { type: string }
      responses:
        '200': { description: OK — events list envelope }
        '402': { description: Payment required }
  /api/x402/v1/signals/{kind}:
    get:
      tags: [signals]
      summary: Live signals filtered to one kind
      description: |
        Drill-down per signal kind (faster + simpler than the
        generic /signals endpoint with `?kind=` when an agent
        only ever cares about one kind, e.g. a Discord bot that
        only re-broadcasts resolution-risk warnings).
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: path
          name: kind
          required: true
          schema:
            type: string
            enum: [momentum, divergence, flow, resolution_risk, news_lag]
        - in: query
          name: limit
          schema: { type: integer, default: 20, maximum: 60 }
        - in: query
          name: min_evidence
          schema: { type: string, enum: [low, medium, high] }
        - in: query
          name: category
          schema: { type: string }
      responses:
        '200': { description: OK — kind-specific signals envelope }
        '402': { description: Payment required }
        '404': { description: Unknown signal kind }
  /api/x402/v1/trades/recent:
    get:
      tags: [markets]
      summary: Raw recent whale trades feed
      description: |
        Last N $5k+ whale trades with side, size, wallet, market.
        Designed for trading bots and Discord/Telegram channel bots
        that re-broadcast significant flow.
      security:
        - orreryApiKey: []
        - x402: []
      parameters:
        - in: query
          name: limit
          schema: { type: integer, default: 20, maximum: 50 }
        - in: query
          name: min_usd
          schema: { type: number, default: 5000, minimum: 1000 }
        - in: query
          name: side
          schema: { type: string, enum: [BUY, SELL] }
      responses:
        '200': { description: OK — trades feed envelope }
        '402': { description: Payment required }
  /api/x402/v1/health:
    get:
      tags: [markets]
      summary: Free health check + endpoint inventory
      description: |
        Always free (`usdc_per_call: 0`, `payment_status: "preview"`).
        Returns the full X402_CATALOG with current pricing,
        whether payment enforcement is on, and live upstream
        Polymarket health. Agents ping this before deciding which
        paid endpoints to call.
      responses:
        '200': { description: OK — health + inventory envelope }
