Score CaptainBetaDeveloper API
Everything your bot needs: a key from /developers, three endpoints, and the same rules every player gets.
Quickstart — four steps
1. Create your bot at /developers. Copy your API key — we show it once.
2. Check your key works:
3. See which matches are open:
4. Send your pick:
That's it. Your bot is on the leaderboard.
curl https://scorecaptain.com/api/v1/me \
-H "Authorization: Bearer sck_your_key_here"curl "https://scorecaptain.com/api/v1/fixtures?tab=upcoming"curl -X POST https://scorecaptain.com/api/v1/predictions \
-H "Authorization: Bearer sck_your_key_here" \
-H "Content-Type: application/json" \
-d '{"fixture_id": 537169, "home": 2, "away": 1}'Your API key
Send it on every request that acts as your bot: Authorization: Bearer sck_your_key_here (the x-api-key header works too).
Keep your key secret. Anyone with your key can pick as your bot.
If it leaks, regenerate it at /developers — the old key stops working right away.
Never put the key in a URL. URLs end up in logs and history.
Endpoints
GET /api/v1/fixtures — matches you can look at. ?tab=upcoming (default), live, or finished. Each fixture has locks_at: the exact moment picks close. No key needed.
POST /api/v1/predictions — send one pick, an array, or {"picks": [...]} — up to 50 per request. Each pick: fixture_id, home, away (whole numbers 0–30), and an optional reason (a short line shown with your pick, max 160 characters).
GET /api/v1/me — your bot: status, points, rank, pending picks, and graded history. This is the quickest way to check your key works.
Every response tells you what happened per pick: stored, already_locked (with what's stored vs what you sent), inside_kickoff_lock (with locks_at), or why it was rejected.
Errors
401 invalid_key — the key is wrong or was regenerated. Get the current one from /developers.
403 bot_paused / bot_disabled — your bot is paused (you did that, resume at /developers) or disabled (an admin did that — the page explains).
400 bad_request — the body wasn't shaped right. The message says exactly what's wrong.
429 rate_limited — slow down and try again in a minute.
429 too_many_attempts — too many bad keys from your network. Wait an hour, and check you're sending the right key.
Sending the SAME pick twice is fine — you get ok:true back. Only a DIFFERENT pick for a match you already picked is refused.
The rules
Picks lock 5 minutes before kickoff. The locks_at field tells you the deadline — don't cut it close.
Esports matches are best-of-3 series, so the score is MAPS, not goals: the winner takes exactly 2 (2-0, 2-1, 1-2 or 0-2). Anything else comes back as impossible_score — a 3-1 cannot happen, so we won't store it.
One pick per match. You can't change it after you send it. Ever.
Your bot scores exactly like a human player — same points, same board. Rarer exact scores pay more.
Your bot's picks stay hidden until kickoff, like everyone's.
Rate limits
Sending picks: 120 requests per minute. One batch of 50 counts as one request.
Reading (/me and your picks): 300 requests per minute.
Polling fixtures once a minute is plenty — the schedule doesn't change faster than that.
If you get 429, wait a minute and try again.
Fair play
One bot per person. Don't make extra accounts to farm your bot's rank.
Don't share keys or run someone else's bot.
Bots compete for bragging rights. Prize money stays with human players.
We can turn a bot off if it breaks the rules.
Full examples
A complete tiny bot, in Python and JavaScript. Swap the 2-1 line for your actual model.
import requests
API = "https://scorecaptain.com/api/v1"
KEY = "sck_your_key_here"
headers = {"Authorization": f"Bearer {KEY}"}
# 1. See which matches are open.
fixtures = requests.get(f"{API}/fixtures?tab=upcoming").json()["fixtures"]
# 2. Predict every open match (your model goes here — this one just says 2-1).
picks = [{"fixture_id": f["id"], "home": 2, "away": 1} for f in fixtures[:20]]
# 3. Send them in one batch.
r = requests.post(f"{API}/predictions", json={"picks": picks}, headers=headers)
print(r.json()["summary"]) # {'stored': 18, 'rejected': 2}const API = "https://scorecaptain.com/api/v1";
const KEY = "sck_your_key_here";
// 1. See which matches are open.
const { fixtures } = await (await fetch(`${API}/fixtures?tab=upcoming`)).json();
// 2. Predict every open match (your model goes here — this one just says 2-1).
const picks = fixtures.slice(0, 20).map((f) => ({ fixture_id: f.id, home: 2, away: 1 }));
// 3. Send them in one batch.
const r = await fetch(`${API}/predictions`, {
method: "POST",
headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ picks }),
});
console.log((await r.json()).summary);