{
 "openapi": "3.0.3",
 "info": {
  "title": "SkipOdds",
  "version": "1.0.0",
  "description": "Fair sports win probabilities: every surveyed bookmaker price averaged and stripped of its margin (de-vigged), so probabilities sum to exactly 100%. 13 sports, 69+ bookmakers. Auth via x-api-key header or ?api_key= query param. Free demo key: skipodds-demo-2026 (100 requests/day, attribution required).",
  "termsOfService": "https://skipodds.com/terms",
  "contact": {
   "email": "hello@skipodds.com",
   "url": "https://skipodds.com"
  }
 },
 "externalDocs": {
  "description": "Human-readable API reference",
  "url": "https://skipodds.com/docs"
 },
 "servers": [
  {
   "url": "https://skipodds.com"
  }
 ],
 "security": [
  {
   "ApiKeyHeader": []
  },
  {
   "ApiKeyQuery": []
  }
 ],
 "components": {
  "securitySchemes": {
   "ApiKeyHeader": {
    "type": "apiKey",
    "in": "header",
    "name": "x-api-key"
   },
   "ApiKeyQuery": {
    "type": "apiKey",
    "in": "query",
    "name": "api_key"
   }
  },
  "schemas": {
   "Consensus": {
    "type": "object",
    "description": "The SkipOdds Index — de-vigged consensus probabilities that sum to 1.",
    "properties": {
     "home": {
      "type": "number",
      "example": 0.501
     },
     "draw": {
      "type": "number",
      "nullable": true,
      "example": 0.2472
     },
     "away": {
      "type": "number",
      "example": 0.2518
     },
     "fair_odds": {
      "type": "object",
      "properties": {
       "home": {
        "type": "number",
        "example": 1.996
       },
       "draw": {
        "type": "number",
        "nullable": true,
        "example": 4.0459
       },
       "away": {
        "type": "number",
        "example": 3.9708
       }
      }
     },
     "books_surveyed": {
      "type": "integer",
      "example": 69
     },
     "margin_removed": {
      "type": "number",
      "example": 0.0501
     }
    }
   },
   "Fixture": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "format": "uuid"
     },
     "home_team": {
      "type": "string",
      "example": "France"
     },
     "away_team": {
      "type": "string",
      "example": "England"
     },
     "match_date": {
      "type": "string",
      "format": "date-time"
     },
     "status": {
      "type": "string",
      "example": "scheduled"
     },
     "stage": {
      "type": "string",
      "nullable": true
     },
     "skipodds": {
      "type": "object",
      "description": "The SkipOdds Index — de-vigged consensus probabilities that sum to 1.",
      "properties": {
       "home": {
        "type": "number",
        "example": 0.501
       },
       "draw": {
        "type": "number",
        "nullable": true,
        "example": 0.2472
       },
       "away": {
        "type": "number",
        "example": 0.2518
       },
       "fair_odds": {
        "type": "object",
        "properties": {
         "home": {
          "type": "number",
          "example": 1.996
         },
         "draw": {
          "type": "number",
          "nullable": true,
          "example": 4.0459
         },
         "away": {
          "type": "number",
          "example": 3.9708
         }
        }
       },
       "books_surveyed": {
        "type": "integer",
        "example": 69
       },
       "margin_removed": {
        "type": "number",
        "example": 0.0501
       }
      }
     }
    }
   }
  }
 },
 "paths": {
  "/v1/fixtures": {
   "get": {
    "summary": "Soccer fixtures with the SkipOdds Index",
    "parameters": [
     {
      "name": "x-api-key",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "API key (or use ?api_key=). Demo key: skipodds-demo-2026 (100 req/day)."
     },
     {
      "name": "competition",
      "in": "query",
      "schema": {
       "type": "string",
       "example": "fifa-world-cup-2026"
      },
      "description": "Competition slug"
     },
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "default": 25
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Fixture list",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "source": {
           "type": "string",
           "example": "SkipOdds"
          },
          "attribution": {
           "type": "string",
           "example": "https://skipodds.com"
          },
          "generated_at": {
           "type": "string",
           "format": "date-time"
          },
          "requests_remaining_today": {
           "type": "integer"
          },
          "tier": {
           "type": "string",
           "example": "standard"
          },
          "competition": {
           "type": "string"
          },
          "fixtures": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "id": {
              "type": "string",
              "format": "uuid"
             },
             "home_team": {
              "type": "string",
              "example": "France"
             },
             "away_team": {
              "type": "string",
              "example": "England"
             },
             "match_date": {
              "type": "string",
              "format": "date-time"
             },
             "status": {
              "type": "string",
              "example": "scheduled"
             },
             "stage": {
              "type": "string",
              "nullable": true
             },
             "skipodds": {
              "type": "object",
              "description": "The SkipOdds Index — de-vigged consensus probabilities that sum to 1.",
              "properties": {
               "home": {
                "type": "number",
                "example": 0.501
               },
               "draw": {
                "type": "number",
                "nullable": true,
                "example": 0.2472
               },
               "away": {
                "type": "number",
                "example": 0.2518
               },
               "fair_odds": {
                "type": "object",
                "properties": {
                 "home": {
                  "type": "number",
                  "example": 1.996
                 },
                 "draw": {
                  "type": "number",
                  "nullable": true,
                  "example": 4.0459
                 },
                 "away": {
                  "type": "number",
                  "example": 3.9708
                 }
                }
               },
               "books_surveyed": {
                "type": "integer",
                "example": 69
               },
               "margin_removed": {
                "type": "number",
                "example": 0.0501
               }
              }
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "invalid_api_key"
          }
         }
        }
       }
      }
     },
     "429": {
      "description": "Daily quota exceeded for this key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "quota_exceeded"
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/fixtures/{id}": {
   "get": {
    "summary": "Single soccer fixture",
    "parameters": [
     {
      "name": "x-api-key",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "API key (or use ?api_key=). Demo key: skipodds-demo-2026 (100 req/day)."
     },
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "format": "uuid"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Fixture",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "source": {
           "type": "string",
           "example": "SkipOdds"
          },
          "attribution": {
           "type": "string",
           "example": "https://skipodds.com"
          },
          "generated_at": {
           "type": "string",
           "format": "date-time"
          },
          "requests_remaining_today": {
           "type": "integer"
          },
          "tier": {
           "type": "string",
           "example": "standard"
          },
          "fixture": {
           "type": "object",
           "properties": {
            "id": {
             "type": "string",
             "format": "uuid"
            },
            "home_team": {
             "type": "string",
             "example": "France"
            },
            "away_team": {
             "type": "string",
             "example": "England"
            },
            "match_date": {
             "type": "string",
             "format": "date-time"
            },
            "status": {
             "type": "string",
             "example": "scheduled"
            },
            "stage": {
             "type": "string",
             "nullable": true
            },
            "skipodds": {
             "type": "object",
             "description": "The SkipOdds Index — de-vigged consensus probabilities that sum to 1.",
             "properties": {
              "home": {
               "type": "number",
               "example": 0.501
              },
              "draw": {
               "type": "number",
               "nullable": true,
               "example": 0.2472
              },
              "away": {
               "type": "number",
               "example": 0.2518
              },
              "fair_odds": {
               "type": "object",
               "properties": {
                "home": {
                 "type": "number",
                 "example": 1.996
                },
                "draw": {
                 "type": "number",
                 "nullable": true,
                 "example": 4.0459
                },
                "away": {
                 "type": "number",
                 "example": 3.9708
                }
               }
              },
              "books_surveyed": {
               "type": "integer",
               "example": 69
              },
              "margin_removed": {
               "type": "number",
               "example": 0.0501
              }
             }
            }
           }
          }
         }
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "invalid_api_key"
          }
         }
        }
       }
      }
     },
     "429": {
      "description": "Daily quota exceeded for this key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "quota_exceeded"
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/fixtures/{id}/movement": {
   "get": {
    "summary": "How the Index moved over time for one soccer fixture",
    "parameters": [
     {
      "name": "x-api-key",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "API key (or use ?api_key=). Demo key: skipodds-demo-2026 (100 req/day)."
     },
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "format": "uuid"
      }
     },
     {
      "name": "hours",
      "in": "query",
      "schema": {
       "type": "integer",
       "default": 24
      },
      "description": "Window; capped at 72 (Demo/Starter/Pro) or 336 (Scale)"
     }
    ],
    "responses": {
     "200": {
      "description": "Timestamped Index snapshots",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "invalid_api_key"
          }
         }
        }
       }
      }
     },
     "429": {
      "description": "Daily quota exceeded for this key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "quota_exceeded"
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/outrights": {
   "get": {
    "summary": "Tournament-winner probabilities, normalised across the still-alive field",
    "parameters": [
     {
      "name": "x-api-key",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "API key (or use ?api_key=). Demo key: skipodds-demo-2026 (100 req/day)."
     },
     {
      "name": "competition",
      "in": "query",
      "schema": {
       "type": "string",
       "example": "fifa-world-cup-2026"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Winner probabilities",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "invalid_api_key"
          }
         }
        }
       }
      }
     },
     "429": {
      "description": "Daily quota exceeded for this key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "quota_exceeded"
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/{sport}/fixtures": {
   "get": {
    "summary": "Fixtures for a non-soccer sport",
    "parameters": [
     {
      "name": "x-api-key",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "API key (or use ?api_key=). Demo key: skipodds-demo-2026 (100 req/day)."
     },
     {
      "name": "sport",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "enum": [
        "tennis",
        "cricket",
        "rugby",
        "baseball",
        "football",
        "basketball",
        "hockey",
        "college-football",
        "college-basketball",
        "mma",
        "boxing"
       ]
      }
     },
     {
      "name": "limit",
      "in": "query",
      "schema": {
       "type": "integer",
       "default": 25
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Fixture list (draw-aware for cricket/rugby; 2-way for mma/boxing)",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "invalid_api_key"
          }
         }
        }
       }
      }
     },
     "429": {
      "description": "Daily quota exceeded for this key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "quota_exceeded"
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/{sport}/fixtures/{id}": {
   "get": {
    "summary": "Single fixture for a non-soccer sport",
    "parameters": [
     {
      "name": "x-api-key",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "API key (or use ?api_key=). Demo key: skipodds-demo-2026 (100 req/day)."
     },
     {
      "name": "sport",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "enum": [
        "tennis",
        "cricket",
        "rugby",
        "baseball",
        "football",
        "basketball",
        "hockey",
        "college-football",
        "college-basketball",
        "mma",
        "boxing"
       ]
      }
     },
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Fixture",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "invalid_api_key"
          }
         }
        }
       }
      }
     },
     "429": {
      "description": "Daily quota exceeded for this key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "quota_exceeded"
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/{sport}/fixtures/{id}/movement": {
   "get": {
    "summary": "Index movement for a non-soccer fixture",
    "parameters": [
     {
      "name": "x-api-key",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "API key (or use ?api_key=). Demo key: skipodds-demo-2026 (100 req/day)."
     },
     {
      "name": "sport",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "enum": [
        "tennis",
        "cricket",
        "rugby",
        "baseball",
        "football",
        "basketball",
        "hockey",
        "college-football",
        "college-basketball",
        "mma",
        "boxing"
       ]
      }
     },
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "hours",
      "in": "query",
      "schema": {
       "type": "integer",
       "default": 24
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Timestamped Index snapshots",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "invalid_api_key"
          }
         }
        }
       }
      }
     },
     "429": {
      "description": "Daily quota exceeded for this key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "quota_exceeded"
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/golf/tournaments": {
   "get": {
    "summary": "Golf tournaments with normalised outright-winner probabilities",
    "parameters": [
     {
      "name": "x-api-key",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "API key (or use ?api_key=). Demo key: skipodds-demo-2026 (100 req/day)."
     }
    ],
    "responses": {
     "200": {
      "description": "Tournament list",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "invalid_api_key"
          }
         }
        }
       }
      }
     },
     "429": {
      "description": "Daily quota exceeded for this key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "quota_exceeded"
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/golf/tournaments/{key}": {
   "get": {
    "summary": "Single golf tournament with the full priced field",
    "parameters": [
     {
      "name": "x-api-key",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "API key (or use ?api_key=). Demo key: skipodds-demo-2026 (100 req/day)."
     },
     {
      "name": "key",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Tournament with per-player probabilities",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "invalid_api_key"
          }
         }
        }
       }
      }
     },
     "429": {
      "description": "Daily quota exceeded for this key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "quota_exceeded"
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/v1/alerts/webhooks": {
   "get": {
    "summary": "List your registered movement-alert webhooks",
    "parameters": [
     {
      "name": "x-api-key",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "API key (or use ?api_key=). Demo key: skipodds-demo-2026 (100 req/day)."
     }
    ],
    "responses": {
     "200": {
      "description": "Webhook list",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "invalid_api_key"
          }
         }
        }
       }
      }
     },
     "429": {
      "description": "Daily quota exceeded for this key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "quota_exceeded"
          }
         }
        }
       }
      }
     }
    }
   },
   "post": {
    "summary": "Register a webhook fired when the Index moves past your threshold",
    "description": "Checked every 15 minutes. Discord webhook URLs receive formatted messages; other HTTPS endpoints receive JSON. Slots: Starter 2, Pro 5, Scale 20.",
    "parameters": [
     {
      "name": "x-api-key",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "API key (or use ?api_key=). Demo key: skipodds-demo-2026 (100 req/day)."
     }
    ],
    "requestBody": {
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "url": {
          "type": "string"
         },
         "sport": {
          "type": "string"
         },
         "threshold": {
          "type": "number"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Registered webhook"
     },
     "401": {
      "description": "Missing or invalid API key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "invalid_api_key"
          }
         }
        }
       }
      }
     },
     "429": {
      "description": "Daily quota exceeded for this key",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "error": {
           "type": "string",
           "example": "quota_exceeded"
          }
         }
        }
       }
      }
     }
    }
   }
  }
 }
}