{
  "openapi": "3.0.3",
  "info": {
    "title": "HalfPoint API",
    "version": "1",
    "description": "Fixtures, live scores, venue mappings, grades and consensus odds for MLB, NBA, NFL, college football, NHL and the Premier League. Every route needs an API key (header X-Api-Key, or ?key=) except /sample/* and /openapi.json. Get a key at https://account.halfpoint.tech/checkout?plan=consensus (a page in a browser: USD 49, 249 or 799 a month for consensus, realtime, risk; 7-day trial for consensus and realtime), or buy an x402 pass, or pay per request with x402 without a key; or try the free sample first. A request without a key answers 402 with the options. Docs for agents: https://docs.halfpoint.tech/agents/ (Markdown: https://docs.halfpoint.tech/llms.txt).",
    "termsOfService": "https://halfpoint.tech/terms",
    "contact": {
      "url": "https://docs.halfpoint.tech"
    }
  },
  "externalDocs": {
    "url": "https://docs.halfpoint.tech",
    "description": "Documentation"
  },
  "servers": [
    {
      "url": "https://fixtures.halfpoint.tech",
      "description": "fixtures, live scores, mappings, grades"
    },
    {
      "url": "https://odds.halfpoint.tech",
      "description": "consensus odds"
    },
    {
      "url": "https://account.halfpoint.tech",
      "description": "account: checkout, keys, x402 passes"
    }
  ],
  "security": [
    {
      "apiKey": []
    },
    {
      "apiKeyQuery": []
    }
  ],
  "tags": [
    {
      "name": "fixtures"
    },
    {
      "name": "odds"
    },
    {
      "name": "sample",
      "description": "Free, without a key: delayed, one league, at most 10 fixtures; 10 requests per minute and 1,000 per day per address and host (IPv6 by /64)."
    },
    {
      "name": "x402",
      "description": "Pay per request or for a pass in USDC, with x402 (Base)."
    }
  ],
  "paths": {
    "/leagues": {
      "servers": [
        {
          "url": "https://fixtures.halfpoint.tech",
          "description": "fixtures, live scores, mappings, grades"
        }
      ],
      "get": {
        "operationId": "listLeagues",
        "summary": "Leagues served",
        "description": "The leagues served, with their names and sports.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/League"
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not modified: the answer is unchanged since the ETag sent in If-None-Match"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "tags": [
          "fixtures"
        ]
      }
    },
    "/fixtures": {
      "servers": [
        {
          "url": "https://fixtures.halfpoint.tech",
          "description": "fixtures, live scores, mappings, grades"
        }
      ],
      "get": {
        "operationId": "listFixtures",
        "summary": "Schedule",
        "description": "A league's fixtures on a date or range of dates: start, teams, status, postponement links. Without a key it can be paid per request with x402 (see x-payment).",
        "parameters": [
          {
            "$ref": "#/components/parameters/leagueRequired"
          },
          {
            "$ref": "#/components/parameters/date"
          },
          {
            "$ref": "#/components/parameters/division"
          },
          {
            "$ref": "#/components/parameters/paymentSignature"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "PAYMENT-RESPONSE": {
                "$ref": "#/components/headers/PaymentResponse"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FixtureList"
                }
              }
            }
          },
          "304": {
            "description": "Not modified: the answer is unchanged since the ETag sent in If-None-Match; never for a request paid with x402, which always gets the answer"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "x402: this payment is in use by another request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "451": {
            "$ref": "#/components/responses/Unavailable"
          },
          "503": {
            "description": "x402: payments are not available yet",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "tags": [
          "fixtures"
        ],
        "x-payment": {
          "protocol": "x402",
          "version": 2,
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "USDC",
          "prices_usd": {
            "x402.consensus": "0.002"
          },
          "plan_parameter": "plan",
          "default_plan": "x402.consensus",
          "note": "The PAYMENT-REQUIRED header is authoritative. x402 version 2 only (PAYMENT-SIGNATURE). Only a 2xx answer is settled."
        }
      }
    },
    "/live": {
      "servers": [
        {
          "url": "https://fixtures.halfpoint.tech",
          "description": "fixtures, live scores, mappings, grades"
        }
      ],
      "get": {
        "operationId": "listLive",
        "summary": "Live games",
        "description": "Games in progress or delayed, and those final within 2 hours: score, period, clock. Without a key it can be paid per request with x402 (see x-payment).",
        "parameters": [
          {
            "$ref": "#/components/parameters/leagueOptional"
          },
          {
            "$ref": "#/components/parameters/division"
          },
          {
            "$ref": "#/components/parameters/paymentSignature"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "PAYMENT-RESPONSE": {
                "$ref": "#/components/headers/PaymentResponse"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FixtureList"
                }
              }
            }
          },
          "304": {
            "description": "Not modified: the answer is unchanged since the ETag sent in If-None-Match; never for a request paid with x402, which always gets the answer"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "x402: this payment is in use by another request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "451": {
            "$ref": "#/components/responses/Unavailable"
          },
          "503": {
            "description": "x402: payments are not available yet",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "tags": [
          "fixtures"
        ],
        "x-payment": {
          "protocol": "x402",
          "version": 2,
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "USDC",
          "prices_usd": {
            "x402.consensus": "0.002"
          },
          "plan_parameter": "plan",
          "default_plan": "x402.consensus",
          "note": "The PAYMENT-REQUIRED header is authoritative. x402 version 2 only (PAYMENT-SIGNATURE). Only a 2xx answer is settled."
        }
      }
    },
    "/live/stream": {
      "servers": [
        {
          "url": "https://fixtures.halfpoint.tech",
          "description": "fixtures, live scores, mappings, grades"
        }
      ],
      "get": {
        "operationId": "streamLive",
        "tags": [
          "fixtures"
        ],
        "summary": "Live games, streamed",
        "description": "Server-sent events (text/event-stream): the current state first (event state per game, the object of /live), then each change (state; remove with {id} once a game left /live); a comment every 30 s. Needs plan realtime or risk (feature stream). Reconnect to start over from the current state; Last-Event-ID is not supported. At most 8 streams open per key, counted with the other stream (2 on a trial): 429 beyond.",
        "parameters": [
          {
            "$ref": "#/components/parameters/leagueOptional"
          },
          {
            "$ref": "#/components/parameters/division"
          }
        ],
        "responses": {
          "200": {
            "description": "An SSE stream",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "description": "Too many requests with this key, or too many streams open for it: 8 at once across /odds/stream and /live/stream (2 while its only plans are trials, or the key's own cap)",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/mappings": {
      "servers": [
        {
          "url": "https://fixtures.halfpoint.tech",
          "description": "fixtures, live scores, mappings, grades"
        }
      ],
      "get": {
        "operationId": "listMappings",
        "summary": "Venue mappings",
        "description": "Each fixture's ids at sources and venues, with the outcome instruments of its markets.",
        "parameters": [
          {
            "$ref": "#/components/parameters/leagueRequired"
          },
          {
            "$ref": "#/components/parameters/date"
          },
          {
            "$ref": "#/components/parameters/division"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FixtureList"
                }
              }
            }
          },
          "304": {
            "description": "Not modified: the answer is unchanged since the ETag sent in If-None-Match"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "tags": [
          "fixtures"
        ]
      }
    },
    "/grades": {
      "servers": [
        {
          "url": "https://fixtures.halfpoint.tech",
          "description": "fixtures, live scores, mappings, grades"
        }
      ],
      "get": {
        "operationId": "listGrades",
        "summary": "Grades",
        "description": "Each ended fixture's grade per market and outcome: win, lose or push. Without a key it can be paid per request with x402 (see x-payment).",
        "parameters": [
          {
            "$ref": "#/components/parameters/leagueRequired"
          },
          {
            "$ref": "#/components/parameters/date"
          },
          {
            "$ref": "#/components/parameters/division"
          },
          {
            "$ref": "#/components/parameters/paymentSignature"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "PAYMENT-RESPONSE": {
                "$ref": "#/components/headers/PaymentResponse"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FixtureList"
                }
              }
            }
          },
          "304": {
            "description": "Not modified: the answer is unchanged since the ETag sent in If-None-Match; never for a request paid with x402, which always gets the answer"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "x402: this payment is in use by another request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "451": {
            "$ref": "#/components/responses/Unavailable"
          },
          "503": {
            "description": "x402: payments are not available yet",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "tags": [
          "fixtures"
        ],
        "x-payment": {
          "protocol": "x402",
          "version": 2,
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "USDC",
          "prices_usd": {
            "x402.consensus": "0.002"
          },
          "plan_parameter": "plan",
          "default_plan": "x402.consensus",
          "note": "The PAYMENT-REQUIRED header is authoritative. x402 version 2 only (PAYMENT-SIGNATURE). Only a 2xx answer is settled."
        }
      }
    },
    "/fixtures/{id}": {
      "servers": [
        {
          "url": "https://fixtures.halfpoint.tech",
          "description": "fixtures, live scores, mappings, grades"
        }
      ],
      "get": {
        "operationId": "getFixture",
        "summary": "One fixture",
        "description": "Everything about one fixture: schedule, live state, mappings and grades.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "nba-261030-mia-cha"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Fixture"
                }
              }
            }
          },
          "304": {
            "description": "Not modified: the answer is unchanged since the ETag sent in If-None-Match"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "tags": [
          "fixtures"
        ]
      }
    },
    "/odds": {
      "servers": [
        {
          "url": "https://odds.halfpoint.tech",
          "description": "consensus odds"
        }
      ],
      "get": {
        "operationId": "listOdds",
        "summary": "Consensus odds",
        "description": "Our consensus: a market-implied probability per outcome, for games starting within 24 hours and those being played, a snapshot rebuilt at most once a second (at most 1 s behind /odds/stream). stop needs plan risk (feature odds.field.betstop), widened feature odds.field.uncertainty. Without a key it can be paid per request with x402 (see x-payment). x402.risk adds stop, widened and range.",
        "parameters": [
          {
            "$ref": "#/components/parameters/leagueOptional"
          },
          {
            "$ref": "#/components/parameters/paymentSignature"
          },
          {
            "name": "plan",
            "in": "query",
            "required": false,
            "description": "Without a key: the plan paid for, x402.consensus, x402.risk (default x402.consensus)",
            "schema": {
              "type": "string",
              "enum": [
                "x402.consensus",
                "x402.risk"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "PAYMENT-RESPONSE": {
                "$ref": "#/components/headers/PaymentResponse"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OddsList"
                }
              }
            }
          },
          "304": {
            "description": "Not modified: the answer is unchanged since the ETag sent in If-None-Match; never for a request paid with x402, which always gets the answer"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "x402: this payment is in use by another request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "451": {
            "$ref": "#/components/responses/Unavailable"
          },
          "503": {
            "description": "x402: payments are not available yet",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "tags": [
          "odds"
        ],
        "x-payment": {
          "protocol": "x402",
          "version": 2,
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "USDC",
          "prices_usd": {
            "x402.consensus": "0.01",
            "x402.risk": "0.03"
          },
          "plan_parameter": "plan",
          "default_plan": "x402.consensus",
          "note": "The PAYMENT-REQUIRED header is authoritative. x402 version 2 only (PAYMENT-SIGNATURE). Only a 2xx answer is settled."
        }
      }
    },
    "/odds/stream": {
      "servers": [
        {
          "url": "https://odds.halfpoint.tech",
          "description": "consensus odds"
        }
      ],
      "get": {
        "operationId": "streamOdds",
        "tags": [
          "odds"
        ],
        "summary": "Consensus odds, streamed",
        "description": "Server-sent events (text/event-stream): the current prices first (event price per fixture), then each change (price; remove with {id, market}); a comment every 30 s. Needs plan realtime or risk (feature stream). Reconnect to start over from the current state; Last-Event-ID is not supported. At most 8 streams open per key, counted with the other stream (2 on a trial): 429 beyond.",
        "parameters": [
          {
            "$ref": "#/components/parameters/leagueOptional"
          }
        ],
        "responses": {
          "200": {
            "description": "An SSE stream",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "description": "Too many requests with this key, or too many streams open for it: 8 at once across /odds/stream and /live/stream (2 while its only plans are trials, or the key's own cap)",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/sample/odds": {
      "servers": [
        {
          "url": "https://odds.halfpoint.tech",
          "description": "consensus odds"
        }
      ],
      "get": {
        "operationId": "sampleOdds",
        "tags": [
          "sample"
        ],
        "summary": "Free sample: consensus odds, delayed",
        "description": "No key. One league's soonest 10 fixtures, consensus without stop and widened, 60 to 120 s old (taken every minute; updated says when). Same shape as /odds. recent is as of when the prices were taken.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/leagueRequired"
          },
          {
            "$ref": "#/components/parameters/src"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OddsList"
                }
              }
            }
          },
          "304": {
            "description": "Not modified: the answer is unchanged since the ETag sent in If-None-Match"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/SampleLimit"
          },
          "503": {
            "description": "Just started: the sample isn't built yet (rare; for a minute or two after a restart it lists no fixtures)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "451": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/sample/fixtures": {
      "servers": [
        {
          "url": "https://fixtures.halfpoint.tech",
          "description": "fixtures, live scores, mappings, grades"
        }
      ],
      "get": {
        "operationId": "sampleFixtures",
        "tags": [
          "sample"
        ],
        "summary": "Free sample: today's fixtures",
        "description": "No key. One league's first 10 fixtures of today (the league's local date). Same shape as /fixtures.",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/leagueRequired"
          },
          {
            "$ref": "#/components/parameters/src"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "Link": {
                "$ref": "#/components/headers/Link"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FixtureList"
                }
              }
            }
          },
          "304": {
            "description": "Not modified: the answer is unchanged since the ETag sent in If-None-Match"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/SampleLimit"
          },
          "451": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/openapi.json": {
      "servers": [
        {
          "url": "https://fixtures.halfpoint.tech",
          "description": "fixtures, live scores, mappings, grades"
        },
        {
          "url": "https://odds.halfpoint.tech",
          "description": "consensus odds"
        }
      ],
      "get": {
        "operationId": "openapi",
        "summary": "This description",
        "security": [],
        "responses": {
          "200": {
            "description": "OpenAPI 3.0",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/x402/pass": {
      "servers": [
        {
          "url": "https://account.halfpoint.tech",
          "description": "account: checkout, keys, x402 passes"
        }
      ],
      "post": {
        "operationId": "buyPass",
        "tags": [
          "x402"
        ],
        "summary": "Buy a pass with x402",
        "security": [],
        "description": "A plan for a period, paid in USDC with x402 (exact scheme, settled before the key is minted). Without PAYMENT-SIGNATURE: 402 with the requirements and the passes. Paid: the subscription, and a new API key once if the payer (or the key sent with X-Api-Key) has none. Access ends when the period does. A key lost later is replaced with POST /x402/key, signed by the paying wallet.",
        "parameters": [
          {
            "name": "plan",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "realtime",
                "risk"
              ]
            }
          },
          {
            "name": "period",
            "in": "query",
            "required": true,
            "description": "24h (realtime, risk), 7d (realtime)",
            "schema": {
              "type": "string",
              "enum": [
                "24h",
                "7d"
              ]
            }
          },
          {
            "name": "src",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/paymentSignature"
          }
        ],
        "x-payment": {
          "protocol": "x402",
          "version": 2,
          "scheme": "exact",
          "network": "eip155:8453",
          "asset": "USDC",
          "prices_usd": {
            "realtime 24h": "15",
            "risk 24h": "49",
            "realtime 7d": "69"
          },
          "note": "The PAYMENT-REQUIRED header is authoritative. x402 version 2 only (PAYMENT-SIGNATURE)."
        },
        "responses": {
          "200": {
            "description": "Paid: the pass",
            "headers": {
              "PAYMENT-RESPONSE": {
                "$ref": "#/components/headers/PaymentResponse"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "plan",
                    "until",
                    "tx"
                  ],
                  "properties": {
                    "plan": {
                      "type": "string"
                    },
                    "until": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "tx": {
                      "type": "string"
                    },
                    "key": {
                      "type": "string",
                      "description": "the new key, shown once; absent if the customer has one"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "402": {
            "description": "Unpaid, or the settlement failed: the requirements in PAYMENT-REQUIRED, and the passes; the body links the terms (terms)",
            "headers": {
              "PAYMENT-REQUIRED": {
                "$ref": "#/components/headers/PaymentRequired"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "passes": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Payer blocked after failed settlements",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "This payment is in use by another request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many paid requests of this payer at once",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "451": {
            "$ref": "#/components/responses/Unavailable"
          },
          "500": {
            "description": "Paid but not recorded: contact us with the transaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "tx": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Payments are not available yet",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/x402/key": {
      "servers": [
        {
          "url": "https://account.halfpoint.tech",
          "description": "account: checkout, keys, x402 passes"
        }
      ],
      "post": {
        "operationId": "replacePayerKey",
        "tags": [
          "x402"
        ],
        "summary": "Replace a lost pass key, signed by the paying wallet",
        "security": [],
        "description": "For a customer known by its payer address (an x402 pass bought without a key): sign with that address (EIP-191 personal_sign) the text \"HalfPoint: replace the API keys of <address>, issued <issued>\", with address as sent and issued the current time (RFC 3339, e.g. 2026-11-02T17:00:00Z), and send it within 10 minutes (a clock up to 2 minutes ahead is accepted). Only for a customer of the address alone (a pass bought without a key); an account with an email logs in by email. Every key of the customer is revoked and a new one returned once. A signature works once. EOA wallets only.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "address",
                  "issued",
                  "signature"
                ],
                "properties": {
                  "address": {
                    "type": "string",
                    "description": "the paying address, 0x and 40 hex digits"
                  },
                  "issued": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "signature": {
                    "type": "string",
                    "description": "65 bytes, hex"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The new key, shown once",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "key"
                  ],
                  "properties": {
                    "key": {
                      "type": "string"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "description": "The signature is not by the address over the text",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No customer of this address alone",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "This signature was used already",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests from this address",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Api-Key",
        "description": "Your key, hp_...: from checkout at https://account.halfpoint.tech"
      },
      "apiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "key",
        "description": "The key as a query parameter, for clients that can't set headers"
      }
    },
    "parameters": {
      "leagueRequired": {
        "name": "league",
        "in": "query",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/LeagueID"
        }
      },
      "leagueOptional": {
        "name": "league",
        "in": "query",
        "required": false,
        "description": "One league; default all",
        "schema": {
          "$ref": "#/components/schemas/LeagueID"
        }
      },
      "date": {
        "name": "date",
        "in": "query",
        "required": false,
        "description": "YYYY-MM-DD, or a range YYYY-MM-DD-YYYY-MM-DD of up to 31 days; the league's local date; default today",
        "schema": {
          "type": "string"
        },
        "example": "2026-10-29"
      },
      "division": {
        "name": "division",
        "in": "query",
        "required": false,
        "description": "cfb only: games with a team of that division",
        "schema": {
          "type": "string",
          "enum": [
            "fbs",
            "fcs"
          ]
        }
      },
      "src": {
        "name": "src",
        "in": "query",
        "required": false,
        "description": "Where you found us (an agent directory, a registry listing), passed on to the checkout link",
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9_.-]{1,64}$"
        }
      },
      "paymentSignature": {
        "name": "PAYMENT-SIGNATURE",
        "in": "header",
        "required": false,
        "description": "An x402 v2 payment for the requirements of the PAYMENT-REQUIRED header (base64 JSON). Without a key, the request is served once the payment is settled.",
        "schema": {
          "type": "string"
        }
      }
    },
    "headers": {
      "ETag": {
        "description": "A hash of the body: send it as If-None-Match to get 304 while unchanged",
        "schema": {
          "type": "string"
        }
      },
      "Link": {
        "description": "Where to go next: the docs for agents (rel=help), this description (rel=describedby), the checkout for a key (rel=payment)",
        "schema": {
          "type": "string"
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait",
        "schema": {
          "type": "integer"
        }
      },
      "PaymentRequired": {
        "description": "x402 v2 payment requirements, base64 JSON: scheme exact, the network, USDC, the amount in its smallest unit, payTo",
        "schema": {
          "type": "string"
        }
      },
      "PaymentResponse": {
        "description": "x402 settlement of the payment, base64 JSON: the transaction",
        "schema": {
          "type": "string"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid parameters",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Unknown key",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "PaymentRequired": {
        "description": "No key, or the key's subscription has lapsed. The body names the ways in: subscribe, an x402 pass, and on routes priced per request the prices; there the PAYMENT-REQUIRED header holds the x402 payment requirements (base64 JSON). Pay by retrying with PAYMENT-SIGNATURE.",
        "headers": {
          "PAYMENT-REQUIRED": {
            "$ref": "#/components/headers/PaymentRequired"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/PaymentOptions"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The key's plan doesn't include this, e.g. not included in plan: stream",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "Unknown fixture",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Too many requests with this key (200 per 10 s per key and host)",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "SampleLimit": {
        "description": "Sample limit of this address exceeded (10 per minute, 1,000 per day, per host)",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          },
          "Link": {
            "$ref": "#/components/headers/Link"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unavailable": {
        "description": "Not available in your country (x402 and the sample)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          }
        }
      },
      "LeagueID": {
        "type": "string",
        "enum": [
          "mlb",
          "nba",
          "nfl",
          "cfb",
          "nhl",
          "epl",
          "bund",
          "laliga",
          "ucl"
        ]
      },
      "League": {
        "type": "object",
        "required": [
          "id",
          "name",
          "sport"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/LeagueID"
          },
          "name": {
            "type": "string"
          },
          "sport": {
            "type": "string"
          }
        }
      },
      "Team": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "abbreviation": {
            "type": "string"
          },
          "division": {
            "type": "string"
          },
          "conference": {
            "type": "string"
          }
        }
      },
      "Fixture": {
        "type": "object",
        "required": [
          "id"
        ],
        "description": "A fixture as the route shows it: /fixtures the schedule fields, /live the game state, /mappings the mappings, /grades the grades, /fixtures/{id} all. Fields without a value are left out.",
        "additionalProperties": true,
        "properties": {
          "id": {
            "type": "string",
            "example": "nfl-261029-car-gb"
          },
          "league": {
            "$ref": "#/components/schemas/LeagueID"
          },
          "date": {
            "type": "string",
            "format": "date-time"
          },
          "teams": {
            "type": "object",
            "properties": {
              "away": {
                "$ref": "#/components/schemas/Team"
              },
              "home": {
                "$ref": "#/components/schemas/Team"
              }
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "Scheduled",
              "Delayed",
              "In Progress",
              "Suspended",
              "Final",
              "Postponed",
              "Cancelled"
            ]
          },
          "original_date": {
            "type": "string",
            "format": "date-time"
          },
          "detail": {
            "type": "string"
          },
          "replaces": {
            "type": "string"
          },
          "replaced_by": {
            "type": "string"
          },
          "final_at": {
            "type": "string",
            "format": "date-time"
          },
          "corrected_at": {
            "type": "string",
            "format": "date-time"
          },
          "scores": {
            "type": "object",
            "additionalProperties": true
          },
          "period": {
            "type": "integer"
          },
          "clock": {
            "type": "string"
          },
          "mappings": {
            "type": "object",
            "additionalProperties": true
          },
          "grades": {
            "type": "object",
            "additionalProperties": true
          },
          "graded_at": {
            "type": "string",
            "format": "date-time"
          },
          "inning": {
            "type": "string",
            "description": "MLB: e.g. Top 7th"
          },
          "count": {
            "type": "object",
            "description": "MLB: balls, strikes, outs",
            "properties": {
              "balls": {
                "type": "integer"
              },
              "strikes": {
                "type": "integer"
              },
              "outs": {
                "type": "integer"
              }
            }
          },
          "bases": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "MLB: occupied bases, e.g. [1, 3]"
          }
        }
      },
      "FixtureList": {
        "type": "object",
        "required": [
          "updated",
          "fixtures"
        ],
        "properties": {
          "updated": {
            "type": "string",
            "format": "date-time"
          },
          "league": {
            "$ref": "#/components/schemas/League"
          },
          "fixtures": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Fixture"
            }
          }
        }
      },
      "Price": {
        "type": "object",
        "required": [
          "home",
          "away",
          "recent",
          "at"
        ],
        "properties": {
          "home": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "away": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "draw": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "moneyline_3way only"
          },
          "recent": {
            "type": "boolean",
            "description": "false: the last price, no current consensus"
          },
          "stop": {
            "type": "boolean",
            "description": "plan risk: the bet stop"
          },
          "widened": {
            "type": "boolean",
            "description": "plan risk: the uncertainty"
          },
          "at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "OddsFixture": {
        "type": "object",
        "required": [
          "id",
          "league",
          "start",
          "markets"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "league": {
            "$ref": "#/components/schemas/LeagueID"
          },
          "start": {
            "type": "string",
            "format": "date-time"
          },
          "markets": {
            "type": "object",
            "properties": {
              "moneyline": {
                "$ref": "#/components/schemas/Price"
              },
              "moneyline_3way": {
                "$ref": "#/components/schemas/Price"
              }
            }
          }
        }
      },
      "OddsList": {
        "type": "object",
        "required": [
          "updated",
          "fixtures"
        ],
        "properties": {
          "updated": {
            "type": "string",
            "format": "date-time"
          },
          "league": {
            "$ref": "#/components/schemas/LeagueID"
          },
          "fixtures": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OddsFixture"
            }
          }
        }
      },
      "PaymentOptions": {
        "type": "object",
        "required": [
          "error",
          "subscribe"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "pay_per_request": {
            "type": "object",
            "properties": {
              "how": {
                "type": "string"
              },
              "prices": {
                "type": "object",
                "additionalProperties": {
                  "type": "string"
                },
                "description": "USD (USDC) by plan"
              }
            }
          },
          "subscribe": {
            "type": "string",
            "description": "the checkout for a key"
          },
          "pass": {
            "type": "string",
            "description": "an x402 pass: a plan for a period, paid in USDC, with a key"
          },
          "docs": {
            "type": "string"
          }
        }
      }
    }
  }
}
