Webhooks

Receive HTTP POST notifications in real time as game events happen

Overview

Webhooks deliver HTTP POST requests to your server when game events occur. Instead of polling the API, you register an endpoint URL and subscribe to the event types you care about. When an event fires, we send a signed JSON payload to your URL.

Manage webhooks through the dashboard or programmatically via API key. The full API is covered by an OpenAPI spec — hand it to your AI coding agent and let it handle setup, monitoring, and receiver scaffolding.

Data Delay

Events may be delayed up to 1 minute from real time.

Plan Limits

FeatureFreeALL-ACCESS
Endpoints110
Deliveries per month100500,000
Available eventsFree events onlyAll events
Retry attempts35
Delivery log retention3 days30 days
Manual retryNoYes

NBA

Events are namespaced as nba.*. A single endpoint can subscribe to events from multiple sports.

Event Types

PayloadEvent TypeDescriptionPlan

MLB

Events are namespaced as mlb.*. A single endpoint can subscribe to events from multiple sports.

Event Types

PayloadEvent TypeDescriptionPlan

NHL

Events are namespaced as nhl.*. A single endpoint can subscribe to events from multiple sports.

Event Types

PayloadEvent TypeDescriptionPlan

NCAAB

Events are namespaced as ncaab.*. A single endpoint can subscribe to events from multiple sports.

Event Types

PayloadEvent TypeDescriptionPlan

NCAAW

Events are namespaced as ncaaw.*. A single endpoint can subscribe to events from multiple sports.

Event Types

PayloadEvent TypeDescriptionPlan

ATP Tennis

Events are namespaced as atp.*. A single endpoint can subscribe to events from multiple sports.

Event Types

PayloadEvent TypeDescriptionPlan

WTA Tennis

Events are namespaced as wta.*. A single endpoint can subscribe to events from multiple sports.

Event Types

PayloadEvent TypeDescriptionPlan

Soccer

Seven soccer leagues share the same event types. Each league uses its own namespace prefix.

LeaguePrefix
English Premier Leagueepl.*
La Ligalaliga.*
Serie Aseriea.*
Champions Leagueucl.*
Bundesligabundesliga.*
Ligue 1ligue1.*
MLSmls.*

Shared Soccer Event Types

Replace {league} with epl, laliga, seriea, ucl, bundesliga, ligue1, or mls. There are no league-specific soccer webhook events beyond the namespace prefix.

PayloadEvent TypeDescriptionPlan

PGA Golf

Events are namespaced as pga.*. A single endpoint can subscribe to events from multiple sports.

Event Types

PayloadEvent TypeDescriptionPlan

Webhook Headers

Every delivery includes the following headers:

HeaderExampleDescription
Content-Typeapplication/jsonAlways JSON
User-AgentBDL-Webhook/1.0BallDontLie webhook user agent
X-BDL-Webhook-Idevt_550e8400...Unique event ID (for deduplication)
X-BDL-Webhook-Timestamp1706108400Unix timestamp of this delivery attempt
X-BDL-Webhook-Signaturev1=abc123...HMAC-SHA256 signature

Signature Verification

Verify that webhook deliveries are authentic by computing an HMAC-SHA256 signature and comparing it to the X-BDL-Webhook-Signature header.

  1. Extract the timestamp from X-BDL-Webhook-Timestamp
  2. Construct the signed message: {timestamp}.{raw_body}
  3. Compute HMAC-SHA256 using your endpoint secret
  4. Compare against the signature (after the v1= prefix) using a constant-time comparison

JavaScript

const crypto = require('crypto');

function verifyWebhook(payload, headers, secret) {
  const timestamp = headers['x-bdl-webhook-timestamp'];
  const signature = headers['x-bdl-webhook-signature'];

  const message = `${timestamp}.${payload}`;
  const expected = 'v1=' + crypto
    .createHmac('sha256', secret)
    .update(message)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Python

import hmac
import hashlib

def verify_webhook(payload: bytes, headers: dict, secret: str) -> bool:
    timestamp = headers['x-bdl-webhook-timestamp']
    signature = headers['x-bdl-webhook-signature']

    message = f"{timestamp}.{payload.decode()}"
    expected = 'v1=' + hmac.new(
        secret.encode(),
        message.encode(),
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(signature, expected)

Retries & Auto-disable

If your endpoint returns a non-2xx status code or the request times out (30s), the delivery is retried with exponential backoff:

AttemptDelay
1st retry30 seconds
2nd retry2 minutes
3rd retry10 minutes
4th retry30 minutes

Free accounts get 3 total attempts (initial + 2 retries). ALL-ACCESS accounts get 5 total attempts (initial + 4 retries).

Auto-disable

Endpoints are automatically disabled after 2 consecutive deliveries where all retry attempts are exhausted. Re-enable them from the dashboard.

Delivery Statuses

StatusDescription
pendingQueued, waiting for first attempt or next retry
deliveringCurrently being sent
deliveredSuccessfully delivered (2xx response)
failedLast attempt failed, retries remaining
exhaustedAll retry attempts used, delivery abandoned

Getting Started

  1. Sign up at app.balldontlie.io
  2. Navigate to the Webhooks tab in your dashboard
  3. Create an endpoint with your URL and desired event types
  4. Send a test event to verify your endpoint is receiving payloads
  5. Store your signing secret securely and implement signature verification

AI & Agents

The Webhooks API is fully programmable via API key, which means AI coding agents can manage your entire webhook lifecycle — creating endpoints, subscribing to events, building receivers, and monitoring delivery health — without you touching the dashboard.

OpenAPI Specification

Give your agent the Webhooks OpenAPI spec and it has everything it needs to work with the API: endpoint schemas, authentication, request/response formats, and event type definitions.

Download webhooks-openapi.yml

What an Agent Can Do

  1. Set up endpoints — create webhook endpoints pointed at your server URL and subscribe to the event types you need
  2. Scaffold a receiver — generate a server (Express, Flask, FastAPI, etc.) that accepts webhook POSTs, verifies signatures, and routes events by type
  3. Monitor health — check GET /webhooks/v1/usage for delivery counts and GET /webhooks/v1/endpoints/:id/deliveries?status=failed for failures
  4. Self-heal — retry failed deliveries, rotate secrets, re-enable disabled endpoints, and adjust event subscriptions

Example Prompt

Paste this into your AI coding tool (Claude Code, Cursor, Windsurf, Copilot, etc.) to get started:

I want to receive real-time NBA scoring alerts via BALLDONTLIE webhooks.

Here is the API spec: https://www.balldontlie.io/webhooks-openapi.yml
My API key is: $BALLDONTLIE_API_KEY

Please:
1. Create a webhook endpoint at https://my-server.com/webhooks/bdl
   subscribed to nba.player.scored and nba.game.ended
2. Write an Express.js server that:
   - Accepts POST /webhooks/bdl
   - Verifies the HMAC-SHA256 signature using the endpoint secret
   - Logs a message for each scoring play with the player name and score
   - Returns 200 on success
3. Send a test event to verify it works

Tips for Agent Workflows

  • The OpenAPI spec includes all 254 event types. Point your agent at GET /webhooks/v1/event-types to discover which events are available for your subscription tier.
  • Store the secret from the create endpoint response immediately — it is only returned on creation and on POST /rotate-secret.
  • Use POST /endpoints/:id/test to send a test event and verify your receiver before live games start.
  • Agents can build event-driven automations on top of webhooks: Discord bots, Slack alerts, SMS notifications, database pipelines, betting triggers, and more.

Start Receiving Live Events

Set up your first webhook in minutes. Free tier includes 100 deliveries per month.