SharpAPI Betting Splits API

Public betting splits — handle % and bet % from DraftKings (recreational) and Circa Sports (sharp-friendly), plus ticket-only percentages derived from BetMGM. Splits are a fixed three-source feature and do not scale with the number of sportsbooks on your plan.

Business capability
Sports, Betting & Fantasy AE-180.80

Operations 2

GET /splits List public betting splits #
GET /splits/history Splits history for one event #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/sharpapi:sharpapi-betting-splits-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

sharpapi-betting-splits-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Sharp Betting Splits API
  version: 3.28.0
  description: Real-time sports betting odds API with +EV detection, arbitrage, middles, and low-hold opportunities.
  contact:
    name: SharpAPI Support
    url: https://sharpapi.io
    email: support@sharpapi.io
  license:
    name: Proprietary
    url: https://sharpapi.io/terms
  x-generated-at: '2026-10-13T20:02:34Z'
  x-commit-sha: 850f5cb
servers:
- url: https://api.sharpapi.io/api/v1
  description: Production
security:
- ApiKeyHeader: []
- BearerAuth: []
tags:
- name: Betting Splits
  description: Public betting splits — handle % and bet % from DraftKings (recreational) and Circa Sports (sharp-friendly), plus ticket-only percentages derived from BetMGM. Splits are a fixed three-source feature and do not scale with the number of sportsbooks on your plan.
paths:
  /splits:
    get:
      operationId: listSplits
      summary: List public betting splits
      description: 'Returns the latest snapshot of public betting splits (handle % and bet %) for every tracked event. Data is sourced from DraftKings (recreational) and Circa Sports (sharp-friendly), refreshed every 5 minutes, plus BetMGM, derived from that book''s own public bet-percentage field (ticket % only — the `handle_pct` object is still present on BetMGM rows, but its `away`/`home` members (`over`/`under` on totals) are `null`) and intermittent. These three are the only splits sources; the set is fixed and independent of which sportsbooks your plan selects. Requires Pro tier or higher: both splits routes are registered under the `splits` tier feature, which the Free and Hobby tiers do not carry.'
      tags:
      - Betting Splits
      parameters:
      - $ref: '#/components/parameters/sport'
      - $ref: '#/components/parameters/league'
      - $ref: '#/components/parameters/sportsbook'
      - $ref: '#/components/parameters/event_id'
      - name: market
        in: query
        description: Filter to events that have splits for a market. Comma-separated.
        schema:
          type: string
          enum:
          - spread
          - total
          - moneyline
        example: spread,moneyline
      - $ref: '#/components/parameters/limit'
      - $ref: '#/components/parameters/offset'
      responses:
        '200':
          description: Paginated list of splits, one entry per (event, sportsbook).
          content:
            application/json:
              schema:
                type: object
                required:
                - data
                - pagination
                - updated_at
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/SplitsGame'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
                  updated_at:
                    type: string
                    format: date-time
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
  /splits/history:
    get:
      operationId: getSplitsHistory
      summary: Splits history for one event
      description: Returns captured splits samples for one event within the retained 48-hour window. No longer-term archive or backfill is available. Use cursor pagination to read the window. Requires Pro tier or higher.
      tags:
      - Betting Splits
      parameters:
      - name: event_id
        in: query
        required: true
        description: Canonical event ID (e.g. `mlb_guardians_orioles_2026-04-16`).
        schema:
          type: string
      - $ref: '#/components/parameters/sportsbook'
      - name: start_time
        in: query
        description: Lower bound for snapshot timestamp. Accepts RFC 3339 (`2026-04-16T13:00:00Z`) or Unix seconds (`1776344602`).
        schema:
          type: string
      - name: end_time
        in: query
        description: Upper bound for snapshot timestamp. Same formats as `start_time`.
        schema:
          type: string
      - name: limit
        in: query
        description: Entries per page, default 100, maximum 200. Larger values clamp to 200. Applies after the sportsbook filter.
        schema:
          type: integer
          minimum: 1
          maximum: 200
          default: 100
      - name: cursor
        in: query
        description: Opaque meta.next_cursor from the previous page. Keep event_id, sportsbook, start_time and end_time unchanged.
        schema:
          type: string
      responses:
        '200':
          description: Snapshots ordered oldest-first.
          content:
            application/json:
              schema:
                type: object
                required:
                - success
                - data
                - meta
                properties:
                  success:
                    type: boolean
                    const: true
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/SplitsHistoryEntry'
                  meta:
                    type: object
                    properties:
                      event_id:
                        type: string
                      total:
                        type: integer
                        description: Number of entries returned in this page.
                      books:
                        type: array
                        items:
                          type: string
                        description: Distinct source sportsbooks present in this response.
                      oldest:
                        type:
                        - string
                        - 'null'
                        format: date-time
                        description: Timestamp bound of this page; null for an empty page.
                      newest:
                        type:
                        - string
                        - 'null'
                        format: date-time
                        description: Timestamp bound of this page; null for an empty page.
                      updated_at:
                        type: string
                        format: date-time
                      limit:
                        type: integer
                      has_more:
                        type: boolean
                      next_cursor:
                        type: string
                        description: Continuation token; empty on the final page.
        '400':
          description: Missing event_id, invalid time bounds, or invalid/filter-mismatched cursor.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: invalid_request
                  message: event_id query parameter is required
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          description: History store temporarily unavailable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    SplitsHistoryEntry:
      type: object
      description: A single timestamped splits snapshot for an event from one source.
      required:
      - book
      - ts
      - timestamp
      properties:
        book:
          type: string
          enum:
          - draftkings
          - circa
          - betmgm
          description: Source sportsbook; history uses book where /splits uses sportsbook. No synthetic consensus history is produced.
        ts:
          type: string
          format: date-time
          description: Snapshot timestamp (RFC 3339).
        timestamp:
          type: number
          description: Snapshot timestamp (Unix seconds, fractional).
        spread:
          type: object
          properties:
            away_line:
              type:
              - number
              - 'null'
              description: Spread line for this side, in the book's own sign convention (e.g. `-1.5`). `null` when the source posted no spread for this event at snapshot time; the key may be absent on BetMGM samples.
            home_line:
              type:
              - number
              - 'null'
              description: Spread line for this side, in the book's own sign convention (e.g. `-1.5`). `null` when the source posted no spread for this event at snapshot time; the key may be absent on BetMGM samples.
            handle_pct:
              type: object
              properties:
                away:
                  type:
                  - number
                  - 'null'
                home:
                  type:
                  - number
                  - 'null'
            bets_pct:
              type: object
              properties:
                away:
                  type:
                  - number
                  - 'null'
                home:
                  type:
                  - number
                  - 'null'
        total:
          type: object
          properties:
            line:
              type:
              - number
              - 'null'
              description: Total (over/under) line. `null` when the source posted no total for this event at snapshot time; the key may be absent on BetMGM samples.
            handle_pct:
              type: object
              properties:
                over:
                  type:
                  - number
                  - 'null'
                under:
                  type:
                  - number
                  - 'null'
            bets_pct:
              type: object
              properties:
                over:
                  type:
                  - number
                  - 'null'
                under:
                  type:
                  - number
                  - 'null'
        moneyline:
          type: object
          properties:
            away_odds:
              type:
              - number
              - 'null'
              description: American odds. `null` when the source has pulled the moneyline for this event while still publishing its split percentages; the key may be absent on BetMGM samples.
            home_odds:
              type:
              - number
              - 'null'
              description: American odds. `null` when the source has pulled the moneyline for this event while still publishing its split percentages; the key may be absent on BetMGM samples.
            handle_pct:
              type: object
              properties:
                away:
                  type:
                  - number
                  - 'null'
                home:
                  type:
                  - number
                  - 'null'
            bets_pct:
              type: object
              properties:
                away:
                  type:
                  - number
                  - 'null'
                home:
                  type:
                  - number
                  - 'null'
        available_metrics:
          type: array
          description: Metrics the source book publishes at all. BetMGM declares bets_pct only; DraftKings and Circa declare bets_pct and handle_pct. Omitted for undeclared books.
          items:
            type: string
            enum:
            - bets_pct
            - handle_pct
    SplitsGame:
      type: object
      description: Public betting splits for a single event from one source sportsbook.
      required:
      - event_id
      - sport
      - league
      - sportsbook
      properties:
        event_id:
          type: string
          description: Canonical event ID (joinable with /odds)
        sport:
          type: string
        league:
          type: string
        sportsbook:
          type: string
          enum:
          - draftkings
          - circa
          - betmgm
          - consensus
          description: 'Source sportsbook for the splits data. `consensus` is a synthetic label, not a sportsbook: when every source covering an event posts identical numbers those rows are merged into one row tagged `consensus`, so a `sportsbook=draftkings` filter does not return them. It is accepted by this endpoint''s `sportsbook` filter but never appears in /api/v1/sportsbooks.'
        away_team:
          type: string
        home_team:
          type: string
        spread:
          type: object
          description: 'Spread market splits. NOTE: `away_odds` and `home_odds` here carry spread *line* values (e.g. -1.5/+1.5), not American odds. Field naming is a known inconsistency vs `/splits/history` which uses `away_line`/`home_line`.'
          properties:
            away_odds:
              type: number
            home_odds:
              type: number
            handle_pct:
              type: object
              description: 'Share of money wagered on each side (0.0-1.0). Both members are `null` on `betmgm` rows: BetMGM publishes a ticket percentage only, so no handle figure exists to report. The keys are always present - only their values are null.'
              properties:
                away:
                  type:
                  - number
                  - 'null'
                  minimum: 0
                  maximum: 1
                home:
                  type:
                  - number
                  - 'null'
                  minimum: 0
                  maximum: 1
            bets_pct:
              type: object
              description: Share of tickets wagered on each side (0.0-1.0). Members are `null` when the source has posted no percentage for this market; observed on `betmgm` rows, whose feed is intermittent. The keys are always present - only their values are null.
              properties:
                away:
                  type:
                  - number
                  - 'null'
                  minimum: 0
                  maximum: 1
                home:
                  type:
                  - number
                  - 'null'
                  minimum: 0
                  maximum: 1
        total:
          type: object
          properties:
            line:
              type: number
            handle_pct:
              type: object
              description: 'Share of money wagered on each side (0.0-1.0). Both members are `null` on `betmgm` rows: BetMGM publishes a ticket percentage only, so no handle figure exists to report. The keys are always present - only their values are null.'
              properties:
                over:
                  type:
                  - number
                  - 'null'
                  minimum: 0
                  maximum: 1
                under:
                  type:
                  - number
                  - 'null'
                  minimum: 0
                  maximum: 1
            bets_pct:
              type: object
              description: Share of tickets wagered on each side (0.0-1.0). Members are `null` when the source has posted no percentage for this market; observed on `betmgm` rows, whose feed is intermittent. The keys are always present - only their values are null.
              properties:
                over:
                  type:
                  - number
                  - 'null'
                  minimum: 0
                  maximum: 1
                under:
                  type:
                  - number
                  - 'null'
                  minimum: 0
                  maximum: 1
        moneyline:
          type: object
          properties:
            away_odds:
              type:
              - number
              - 'null'
              description: American odds. `null` when the source has pulled the moneyline for this event while still publishing its split percentages; the key stays present.
            home_odds:
              type:
              - number
              - 'null'
              description: American odds. `null` when the source has pulled the moneyline for this event while still publishing its split percentages; the key stays present.
            handle_pct:
              type: object
              description: 'Share of money wagered on each side (0.0-1.0). Both members are `null` on `betmgm` rows: BetMGM publishes a ticket percentage only, so no handle figure exists to report. The keys are always present - only their values are null.'
              properties:
                away:
                  type:
                  - number
                  - 'null'
                  minimum: 0
                  maximum: 1
                home:
                  type:
                  - number
                  - 'null'
                  minimum: 0
                  maximum: 1
            bets_pct:
              type: object
              description: Share of tickets wagered on each side (0.0-1.0). Members are `null` when the source has posted no percentage for this market; observed on `betmgm` rows, whose feed is intermittent. The keys are always present - only their values are null.
              properties:
                away:
                  type:
                  - number
                  - 'null'
                  minimum: 0
                  maximum: 1
                home:
                  type:
                  - number
                  - 'null'
                  minimum: 0
                  maximum: 1
        fetched_at:
          type: string
          format: date-time
        available_metrics:
          type: array
          description: 'Which public-betting split metrics this row''s sportsbook publishes AT ALL. This is a per-book declaration, not a description of the values this particular row happens to hold, and it is serialised in the order shown. Omitted entirely when SharpAPI has not declared what the book publishes: an absent field means ''not stated'', never ''publishes nothing''. Read it together with the value - `handle_pct` listed while its members are `null` is a number we are missing, whereas `handle_pct` absent from this list while its members are `null` means the book does not publish money share. A synthetic `consensus` row carries the intersection of its contributing books, and omits the field if any contributor is undeclared.'
          items:
            type: string
            enum:
            - bets_pct
            - handle_pct
    Pagination:
      type: object
      required:
      - limit
      - offset
      - has_more
      - next_offset
      properties:
        limit:
          type: integer
        offset:
          type: integer
        count:
          type: integer
          description: Length of the current `data` page.
          example: 50
        total:
          type: integer
          description: Size of the full matching set. Emitted where the endpoint computes it (`/events` does); `/odds` omits it.
          example: 1247
        has_more:
          type: boolean
        next_offset:
          type:
          - integer
          - 'null'
    ErrorResponse:
      type: object
      required:
      - error
      properties:
        error:
          type: object
          required:
          - code
          - message
          properties:
            code:
              type: string
              enum:
              - missing_api_key
              - invalid_api_key
              - unauthorized
              - forbidden
              - tier_restricted
              - rate_limited
              - invalid_request
              - validation_error
              - not_found
              - streaming_not_available
              - stream_limit_exceeded
              - service_unavailable
              - internal_error
              description: Machine-readable error code
            message:
              type: string
              description: Human-readable error message
            docs:
              type: string
              format: uri
              description: Link to relevant documentation
            tier:
              type: string
              description: Current subscription tier
            required_tier:
              type: string
              description: Minimum tier required for this feature
            retry_after:
              type: integer
              description: Unix timestamp (ms) when request can be retried
            retryAfter:
              type: integer
              description: Seconds until the request can be retried — same instant as retry_after, different unit and casing
            max_books:
              type: integer
            requested_books:
              type: integer
  parameters:
    event_id:
      name: event_id
      in: query
      description: 'Filter by event ID (comma-separated). `event_id` is the canonical name. The legacy spellings `event`, `events` and `event_ids` are still accepted, but a request that uses one is answered with `Deprecation: true` and `Warning: 299 - "filter alias(es) ... deprecated; use event_id"`. No `Sunset` date is sent. Send `event_id` to avoid those headers.'
      schema:
        type: string
    sport:
      name: sport
      in: query
      description: Filter by sport (comma-separated)
      schema:
        type: string
      example: basketball
    sportsbook:
      name: sportsbook
      in: query
      description: 'Filter by sportsbook (comma-separated). **Intentionally not enumerated.** This one parameter definition is shared by eleven operations, and they do not accept the same set of values, so no single `enum` would be correct for all of them. Nine of them validate the value and answer `400 invalid_filter` for one they do not accept; the other two do not reject an unrecognised value at all — `/splits/history` returns no rows for it and `/stream` opens the stream. See `/sportsbooks` for the book roster. The clearest per-operation difference is the synthetic `consensus` value: it is meaningful only on `/splits`, and every other operation that validates this filter rejects it.'
      schema:
        type: string
      example: draftkings,fanduel
    offset:
      name: offset
      in: query
      description: Number of results to skip
      schema:
        type: integer
        default: 0
        minimum: 0
    limit:
      name: limit
      in: query
      description: Maximum results per page
      schema:
        type: integer
        default: 50
        minimum: 0
        maximum: 500
    league:
      name: league
      in: query
      description: Filter by league (comma-separated)
      schema:
        type: string
      example: nba
  responses:
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            missing:
              summary: Missing API key
              value:
                error:
                  code: missing_api_key
                  message: API key required
                  docs: https://docs.sharpapi.io/en/authentication#authentication-methods
            invalid:
              summary: Invalid API key
              value:
                error:
                  code: invalid_api_key
                  message: Invalid API key
                  docs: https://docs.sharpapi.io/en/authentication#authentication-methods
    RateLimited:
      description: Rate limit exceeded
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
        Retry-After:
          description: Seconds until the rate limit resets
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: rate_limited
              message: Rate limit exceeded
              retry_after: 1709993460000
              retryAfter: 3
              docs: https://docs.sharpapi.io/en/authentication#rate-limits
  headers:
    X-RateLimit-Limit:
      description: Maximum requests allowed per minute
      schema:
        type: integer
    X-RateLimit-Reset:
      description: Unix timestamp (ms) when the rate limit window resets
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: Requests remaining in the current window
      schema:
        type: integer
  securitySchemes:
    ApiKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key passed in the `X-API-Key` header
    BearerAuth:
      type: http
      scheme: bearer
      description: API key passed as a Bearer token in the `Authorization` header
    ApiKeyQuery:
      type: apiKey
      in: query
      name: api_key
      description: API key as query parameter (for SSE/EventSource only)