Onboarding — Game Value, team board

Nine steps, each with a way to tell that it worked. Follow them in order and your values are scored. Skip one and everything still returns 201 — and nothing is ever scored.

This is the page to read end to end before you write any code. The delivery contract is the reference you will keep open afterwards; the overview explains what is being measured and why.

This is not one submission

The Transfers benchmark is answer-once-and-wait: you fetch the open cases, submit one file, and are scored. You can hold the whole obligation in your head.

Team Value is a standing weekly obligation against a fixture list that moves. After every round you send one number per team per match, before a deadline that belongs to the round rather than to the match, and your score is rebuilt from the whole season each week. There is no single submission that finishes the job.

Two consequences worth knowing before you start:

  • The gap between "my integration works" and "I am being scored" is real. A delivery can be accepted in full and still contribute nothing, because a value counts only toward fixtures kicking off after its deadline. That rule is what stops anyone pricing a match whose result they already know, and it is the single most common reason a correct-looking integration scores zero fixtures.
  • From registering to a first score is weeks, not days. A fixture is scored only once both sides have enough delivered history behind them, at all three horizons. Your first rounds build that history and score nothing. This is by construction, not a fault in your setup.

Step 1 — Register

One identity for the whole Arena, whatever you enter.

POST /api/participants
{
  "vendor_name": "Acme Analytics",
  "leaderboard_name": "Acme values",
  "short_description": "Possession value model",
  "contact_email": "team@acme.example.com"
}

The response carries an API key beginning fa_. It is shown once and never again — store it where your delivery job can read it. The contact address is where deadline reminders and delivery problems are sent; it is never published.

Done when you hold a key starting fa_ and the confirmation email has arrived. The key is Arena-wide: the same one enters and delivers to every benchmark.

Step 2 — Enter the benchmark

Registering gives you an identity. Entering says which benchmark that identity is competing in.

POST /api/participants/entries        Authorization: Bearer <your key>
{ "task_slug": "game_value_team" }

A 201 comes back with "participation_mode": "submission" — the Arena never calls you, so there is no endpoint to expose and no service to keep running. Your job delivers to us.

Done when you have that 201.

Entering is not certifying. A real delivery now is refused with 403 Certify first. Step 4 is what enrolment actually means.

Step 3 — Integrate the identifiers

Everything you deliver is keyed on the Arena's identifiers. Map them to your own once, before you send anything.

GET /api/tasks/game-value-team/teams        the registry: team_id -> club, country, competition
GET /api/tasks/game-value-team/fixtures     the schedule: match_id, both team ids, kickoff, deadline

The team registry gives each team_id (FAT00066) a club name, country and competition. The fixture list gives each match_id (fam_2627_premierleague_0042) its round, kick-off in Europe/Paris, both team ids — with their names beside them for reading — its status, and the deadline its round is due at.

Three things to build into your job now rather than later:

  • Integrate on the ids, never the names. Club names are published so a row is readable; they are not accepted in a delivery. A name match is a guess, and a guess attaches a value to the wrong club silently.
  • Re-read the fixture list every run. It is live: postponements, rescheduled kick-offs and awarded results appear as they happen. Pass ?since= with the largest updated_at you hold to read only what changed.
  • match_id is stable through any reschedule. A postponed match keeps its identifier and gets a new kick-off and its own deadline.

A ?competition= filter takes the exact published name — Premier League, LaLiga, Serie A, Bundesliga, Ligue 1 — and anything else is refused with the valid names rather than answered with an empty list.

Done when every club you cover resolves to a team_id in your own database, and you can list the fixtures of the current round without consulting a name.

Step 4 — Certify

Certification is a dry run against one completed round, checked exactly as a real delivery would be and storing nothing.

POST /api/tasks/game-value-team/values?dry_run=true       Authorization: Bearer <your key>
{
  "task": "game_value_team",
  "contract_version": "2026-09-game-value-team-v0",
  "model_version": "my-model-1.4",
  "values": [
    {"match_id": "fam_2627_premierleague_0042", "team_id": "FAT0000042", "value": 1.83},
    {"match_id": "fam_2627_premierleague_0042", "team_id": "FAT0000117", "value": 1.21}
  ]
}

To pass, the dry run must cover every match of one completed round in a competition, both sides of each, and nothing may be rejected.

late is not a failure. Certification runs against a round whose deadline has passed, so its entries come back marked late. That is expected and correct. The only outcome that prevents certification is rejected.

Certifying is also how you declare what you are entering. The competitions your dry run covered are the ones you will be scored on, and coverage within a competition is all or nothing — you cannot enter the half of a league you like. If you intend to cover all five, send one complete round per competition.

Done when the receipt says "certified": true. That moment is your enrolment: you are scored from it, not from when you registered.

Dry runs count toward no limit, so run as many as you need until nothing is rejected.

Step 5 — Deliver, every round

The same call without dry_run. One number per team per match: what that team's performance was worth, on your own scale.

POST /api/tasks/game-value-team/values        Authorization: Bearer <your key>
  • Nothing is normalised. The score depends only on the order your values put fixtures in, so there is no scale to match and no units to agree on.
  • Both sides of a fixture must travel together. One side alone is refused: a fixture priced on one side has no net value for either team.
  • Only played matches. A status of played or awarded can be priced; a scheduled one cannot.
  • A delivery may carry any number of matches, from one round or several.

The response is your receipt: an outcome for every entry — accepted, replaced, unchanged, late, or rejected with a reason — plus the Arena's receipt time and a payload_sha256 of the body as received. Time is the Arena's; your own timestamps are not read.

You may store three deliveries per round. Dry runs are exempt.

Done when the receipt's outcomes are the ones you expected and its payload_sha256 matches the checksum of what you sent. Keep the receipt: it is what proves what you delivered and when.

Step 6 — Know your deadline

The deadline belongs to the round, not to the match, and every fixture carries it before it is played.

  • A round's values are due at 23:59 Europe/Paris, a full day after the round's last match — Tuesday, for a weekend round.
  • A postponed match is a round of its own and carries its own deadline.
  • Values are replaceable until the deadline and freeze at it. Afterwards a first value still lands, marked late; a different value for something already delivered is refused as frozen.
  • A value counts only toward fixtures kicking off after its deadline. This is what makes the benchmark a forecast rather than a description.

The reason for the day's delay is that match data is not final at the whistle. You are meant to correct a value during that window; that is what it is for.

Done when your job runs on a schedule that clears the deadline with room to spare — not on the final whistle, and not at 23:50.

Step 7 — Check what is still missing

GET /api/tasks/game-value-team/status        Authorization: Bearer <your key>

due lists every open round with something outstanding: its competition, round, deadline, how many values are expected, how many arrived, which (match_id, team_id) pairs are absent, and how many of that round's three deliveries remain. missed_this_season counts values that were not there when a deadline passed.

Reads are free and count toward no limit, so call it after every run. The Arena also emails a reminder before a deadline where something is still missing — but a job that checks its own work does not need to be chased.

Done when due is empty for the open round.

Step 8 — Be scored

The scoring run is every Saturday at 06:00 Europe/Paris, after the previous round's results are final. It rebuilds your score from the whole season and appends one immutable snapshot per week.

A fixture is scored for you only when:

  • both sides were priced by you, before the deadline;
  • both sides have enough delivered history behind them to build a signal at all three horizons.

The second condition is why your first rounds score nothing. Each round you deliver adds to the history the next fixtures are ordered from, and once both sides of a fixture have enough, it counts. Expect the first snapshot some weeks after your first delivery, not on the first Saturday.

Done when a snapshot exists for you. Until it does, you are enrolled and delivering correctly — there is simply nothing to compute yet.

Step 9 — Be published

Being scored and being named are separate. A person confirms who you are before your row appears on the public board.

Publication is resolved when the board is read, not captured into your snapshots, so confirming late reveals your whole trajectory at once. Being published slowly costs you nothing.

Done when your row is on the team board.


Your first month

What actually happens, week by week, if you certify today.

WhenWhat happensWhat you should see
Day 0Register, enter, integrate, certify"certified": true, and enrolment dated now
The first round after thatYour job delivers for every match playedA receipt with entries accepted
That Tuesday 23:59The round's values freezestatus shows nothing due
The first SaturdayScoring runsNo snapshot yet — too little history
Weeks 2–3Deliver every roundstatus empty each week; still no snapshot
Around week 4Both sides of some fixtures now have enough historyYour first snapshot, and a skill score with an interval
After thatWeeklyOne snapshot a week, and a trajectory

Common refusals, and what each means

A whole delivery can be refused:

CodeMeansFix
401No valid keySend Authorization: Bearer <your key>
403Not entered, or not certifiedStep 2, then step 4
400Wrong taskIt must be game_value_team
409contract_version is not the one in forceThe refusal names the version that is; see versioning
422The body is not shaped like the contractCheck required fields and types

Or individual entries can be rejected while the rest of the delivery lands:

ReasonMeansFix
unknown match_idNo such fixture this seasonRe-read /fixtures; do not construct identifiers
team did not play in this matchThe team is not one of the two sidesCheck your id mapping — this is usually a name match gone wrong
match not playedPriced before it was playedDeliver after the match, not before
before enrolmentThe match predates your certificationNot accepted: it could be priced knowing the result
value is not a numberThe value is not numericSend a number, not a string or null
frozenA different value after the deadlineThe first value stands; corrections had to arrive before the deadline
delivery limit reached for this roundA fourth stored deliveryThree per round; batch your corrections
fixture described on one side onlyOnly one team pricedSend both sides together

Joining mid-season

You may join at any point. Certify, and you are scored from that moment.

Values for matches that kicked off before you certified are refused as before enrolment. This is not a penalty for arriving late — it is the same rule everyone is under. A value for a match played weeks ago could be priced knowing every result since, and would not be a forecast.

The consequence is worth planning for: you build your delivered history from the day you certify, so the sooner you certify, the sooner the first fixture has enough behind it to be scored.

Before your first real delivery

  • Your key is stored where the job reads it, and is not in source control
  • Every club you cover maps to a team_id, and nothing is matched by name
  • Your job re-reads /fixtures each run and handles a changed kick-off
  • You price only played and awarded matches
  • Both sides of every fixture are in the same delivery
  • contract_version is the one in force, and a 409 is treated as a change to act on
  • Your schedule clears the deadline by hours, not minutes
  • You keep each receipt, with its payload_sha256
  • You call /status after each run and alert on anything due
  • You have certified one complete round per competition you intend to cover
  • Delivery contract — the reference for every call above, with the deadline rules in full.
  • Overview — what is measured, and why agreeing with the scoreline is not evidence.
  • Reading a leaderboard — how to read a skill score and its interval.
  • The team board — what a published participant looks like.