draftkings apiDashboard ↗

INDEPENDENT DEVELOPER REFERENCE

Build a DraftKings data Discord bot

Post recorded Pick6 changes to a Discord channel with an incoming webhook: polling, cursors, quota math and message wording.

Editorial review: · Not a live coverage report

What to build

The simplest useful bot is one scheduled script: read new Pick6 changes, format each one, and post it to a Discord incoming webhook. It needs no bot account, no gateway connection and no extra dependencies. It reports recorded data and should never tell readers what to enter.

Set up the two secrets

Create a webhook in your Discord channel settings under Integrations, and copy its URL. Treat that URL as a secret, since anyone holding it can post to the channel. Keep both values in the environment.

Start with a dry run
export DRAFTKINGS_API_KEY='dk_...'
export DISCORD_WEBHOOK_URL='https://discord.com/api/webhooks/...'

node discord-alerts.mjs --sport NHL --stat "Shots on Goal" --dry-run

--dry-run prints messages rather than sending them, so you can check the wording and volume first. The alert bot uses only built-in Node.js modules, and it stores its cursor in a state file.

Poll with a saved cursor

Read /api/v1/pick6/history with after set to your stored cursor. Post the rows, then save pagination.next_after. Saving last means a crash can repeat a message but cannot lose one.

Core loop, without error handling
const url = new URL("/api/v1/pick6/history", BASE);
url.searchParams.set("sport", "NHL");
url.searchParams.set("stat", "Shots on Goal");
url.searchParams.set("after", String(state.after));
url.searchParams.set("limit", "25");
const page = await (await fetch(url, {
  headers: { Authorization: `Bearer ${KEY}` },
  signal: AbortSignal.timeout(20_000),
})).json();

for (const row of page.data) await postToDiscord(formatChange(row));
state.after = page.pagination.next_after;
await saveState(state);

Start after from 0 only if you want the backlog posted. Otherwise page to the latest cursor once with posting disabled, then begin. Without this, your first run could post every retained change.

Do the quota math first

Decide your schedule from your plan's allowance, not from how fast you would like updates. Pick6 worker targets are five minutes, so polling more often returns no newer data.

PlanRequests per monthEven spacing if this job is your only traffic
Free500One request every 86 minutes
Developer10,000One request every 4.3 minutes
Production50,000One request every 0.9 minutes

A 5-minute poll is about 8,640 requests in a 30-day month. That uses most of Developer and is far beyond Free, where one poll every few hours is more realistic. Limit each run to a few pages, and raise the interval when other jobs share the key's account. On Developer and above, the stream is an alternative for a long-running process, though each connection also costs a request.

Respect Discord's limits

Discord rate-limits webhooks and replies with 429 and a retry delay. Send messages one at a time, honor Retry-After, and combine many changes into one message rather than a post for each. Cap messages per run, and log how many changes you held back.

Posting with a retry
async function postToDiscord(content) {
  for (let attempt = 0; attempt < 3; attempt++) {
    const response = await fetch(process.env.DISCORD_WEBHOOK_URL, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ content, allowed_mentions: { parse: [] } }),
      signal: AbortSignal.timeout(10_000),
    });
    if (response.status !== 429) return response.ok;
    const wait = Number(response.headers.get("retry-after") ?? 2);
    await new Promise((r) => setTimeout(r, wait * 1000));
  }
  return false;
}

allowed_mentions with an empty parse list stops source text from pinging the channel.

Write factual messages

State what was recorded and when. Do not recommend a side, say a line is good value, predict a result or use betting call-outs. This service does not place, recommend or settle entries or bets, and your bot's wording should not suggest otherwise.

Illustrative message, not a real record
Recorded change, NHL Shots on Goal
EXAMPLE PLAYER: target 1.5 -> 2.5
More: 1x -> 1.3x
Observed 2026-11-03 18:24 UTC. Standings multiplier, not odds. Not an offer.
  • Include observed_at in every message.
  • Skip or mark rows with is_paused: true.
  • Describe multipliers as standings multipliers, not odds.
  • Say that the feed is selected captures, not the whole board.

Public servers and redistribution

Posting to a private channel for yourself is different from running a public or paid server. Technical access is not a redistribution license, so posting data to a large or commercial audience is your rights question to review first. If you do run a public bot, show the disclaimer that it is independent, not affiliated with or endorsed by DraftKings, and contains no wagering advice. Local gambling and advertising rules may apply to you as well.

Try it

Run a dry run before connecting a channel: node discord-alerts.mjs --sport NHL --stat "Shots on Goal" --dry-run.

Check the recorded data

Questions

Do I need a Discord bot account?

No. A channel incoming webhook is enough for posting messages. You need a bot account only if people must run commands that trigger lookups.

How often should my bot poll?

Pick6 worker targets are five minutes, so polling more often adds no newer data. On Free, poll far less often, because 500 monthly requests is roughly one call every 86 minutes.

Can the bot alert on sportsbook lines?

It can poll /api/v1/history on the same pattern with offset paging, ordered by seq. Sportsbook data is mainlines only, and there is no push delivery for it.

Can I run this bot on a public server?

Check your rights first. An API key gives technical access and is not a redistribution license. State clearly that the bot is independent and offers no wagering advice.

Related resources

Independent service operated by DD Inc., not affiliated with or endorsed by DraftKings. Technical access is not a redistribution license. No wagering: this service does not place, recommend or settle entries or bets. Check sources and status for actual capture context.