Onboarding — Game Value, player board

Ten steps, each with a way to tell that it worked. Follow them in order and your ratings 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.

Every call below is made against https://api.footballanalyticsarena.com, and paths are shown relative to it. The API's own reference, where each endpoint can be tried from the browser, is at api.footballanalyticsarena.com/docs.

This is not one submission

Player Value is a standing weekly obligation, at the scale of a squad sheet. After every round you send one rating per player per appearance — about 1,400 of them — before a deadline that belongs to the round rather than to the match, and your score is rebuilt from the whole season each week.

If you already deliver to the team board, the rules are the same ones to the minute: the same key, the same deadlines, the same freeze, the same ten deliveries a round. Three things are different, and all three follow from the number:

  • The unit is an appearance, so the list pages. You follow it with a cursor rather than reading it whole (step 4).
  • The gate is the eleven, not everything. Certification asks for every starter; a cameo you decline does not block you (step 5).
  • A rating is scored through the eleven it played in. A segment is priced on the mean prior rating of the players on the pitch, so a rating counts once a player has an earlier rated appearance behind him — not the week you send it (step 9).

Step 1 — Register

One identity for the whole Arena, whatever you enter.

POST /api/participants
{
  "vendor_name": "Acme Analytics",
  "leaderboard_name": "Acme ratings",
  "short_description": "Match ratings from event data",
  "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 are sent; it is never published.

Done when you hold a key starting fa_. If you are already registered for another benchmark, skip this: the key is Arena-wide.

Step 2 — Enter the benchmark

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

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.

Done when you have that 201.

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

Step 3 — Map the Arena's players to your own

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

GET /api/tasks/game-value-team/teams          the clubs: team_id -> name, country, competition
GET /api/tasks/game-value-player/players      the players: player_id -> name, club, birth year, position

The team registry is the team board's, because both boards share one calendar and one set of club ids. The player directory gives each player_id (FAP0003133) the name, club, year of birth, nationality and position you need to match it against your own database. Both are public: no key. ?team_id= or ?competition= reads one club or one league at a time.

  • Integrate on the ids, never the names. Names are published so you can build the mapping; a delivery carries player_id alone. A name match made at delivery time is a guess, and a guess puts a rating on the wrong footballer silently.
  • Match on more than a name. Club, birth year and position resolve the cases a name cannot — two players of one name in one league, the player a source spells three ways.
  • New players arrive every window. Re-read the directory weekly and map what is new; a player you have not mapped is an appearance you cannot rate.

Done when every club you cover resolves to a team_id, and the players of those clubs resolve to player_ids in your own database without consulting a name at delivery time.

Step 4 — Follow the appearance list

GET /api/tasks/game-value-player/appearances?limit=1000        Authorization: Bearer <your key>

One row per player per appearance: match_id, player_id, team_id, minutes_played, is_starter, competition, round, kickoff, deadline, updated_at. It is what you rate, and the only thing you can rate — a rating for anyone not on it is refused.

Page it with the cursor, not with a timestamp. The response carries count, more and next_since. While more is true, send next_since back as ?since= to get the next page. At the end of the list, keep the next_since you were given and send it on your next run: you will read only what changed.

Why this matters. A match's appearances are all written at the same instant. A page that ends in the middle of a match ends on a time that the unread rows of that match also carry, so resuming on the time alone skips them — silently, and for good. next_since names the exact row you stopped on. It is the easiest thing on this board to get wrong.

Two things the list decides for you:

  • An unused substitute is not on it. He made no appearance; there is nothing to rate.
  • A three-minute substitute is. He played. Declining to rate him is a product boundary the board reports as coverage, not an error.

Done when your job reads the whole list in pages, stores next_since, and a second run straight after the first returns nothing new.

Step 5 — 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-player/ratings?dry_run=true        Authorization: Bearer <your key>
{
  "task": "game_value_player",
  "contract_version": "2026-09-game-value-player-v0",
  "model_version": "my-ratings-2.1",
  "ratings": [
    {"match_id": "fam_2627_premierleague_0042", "player_id": "FAP0000731", "rating": 7.4},
    {"match_id": "fam_2627_premierleague_0042", "player_id": "FAP0004120", "rating": 5.9}
  ]
}

To pass, the dry run must carry every starter of one completed round, and nothing may be rejected. Send the whole round — cameos included, where you rate them — but only the starters are required: the eleven on the pitch at kick-off is what a signal is built from.

late is not a failure. A completed round's deadline has passed, so its entries come back marked late. 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 are scored on, and within one you rate every appearance you can — you do not choose which. To cover all five leagues, send one completed round per competition in the same dry run. Certifying again later adds a competition; it never moves your enrolment date.

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 6 — Deliver, every round

The same call without dry_run: one number per player per appearance, on your own scale.

POST /api/tasks/game-value-player/ratings        Authorization: Bearer <your key>
  • Nothing is normalised. Out of ten, out of a hundred, z-scores: the score depends only on the order your ratings put players in.
  • One rating per appearance, not per segment. The Arena decides who was on the pitch for each segment, from the event stream.
  • A missing rating is missing, never zero. Leave out what you do not rate. A zero for a player you did not judge is a wrong number, and on a mean over eleven a very wrong one.
  • Goalkeepers are not optional. An unrated keeper counts against your rated share like anyone else.

The response is your receipt: an outcome per entry — accepted, replaced, unchanged, late, or rejected with a reason — the Arena's receipt time, and a payload_sha256 of the body as received.

Ten stored deliveries per round, dry runs exempt. A round is about 1,400 ratings, so batch them: a job that re-posts the same round every night spends the ten inside a fortnight.

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.

Step 7 — Know your deadline

The deadline belongs to the round, not to the match, and every appearance carries it.

  • A round's ratings are due at 23:59 Europe/Paris, a full day after the round's last match — Tuesday, for a weekend round. The same rule as the team board.
  • A postponed match is a round of its own, with its own deadline.
  • Ratings are replaceable until the deadline and freeze at it. Afterwards a first rating still lands, as late; a different rating for someone already rated is refused as frozen.
  • A rating counts only toward matches kicking off after its deadline. A rating that can arrive once a result is known must not be allowed to inform it.

Run your job daily, not weekly. A midweek round is due the day after it is played, and a weekly job misses one deadline in every midweek week.

Done when your job runs daily and clears each deadline by hours, not minutes.

Step 8 — Check what is still missing

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

due lists every open round with something missing: its competition, round and deadline, how many ratings are expected and how many were delivered, how many are missing, which matches they are missing from (matches_incomplete), and the deliveries_left for that round. missed_this_season counts ratings that were not there when a deadline passed.

What is missing is counted, not listed — a list of 1,400 outstanding appearances would be longer than the delivery that answers it. matches_incomplete tells you where to look.

The Arena also emails a reminder at deadline − 12 h and − 3 h when something is missing. A job that checks its own work never hears from us.

Done when due is empty for the open round, or holds only the cameos you choose not to rate.

Step 9 — Be scored

The scoring run is every Saturday at 06:30 Europe/Paris, once every deadline in the week has passed. It rebuilds your score from the whole season and appends one immutable snapshot a week.

A segment is scored for you only when at least nine of the eleven on the pitch, on both sides, have a prior rating from you — a rating for an earlier appearance, due before this match kicked off. That is why your first round scores nothing: it is the history your second round is priced on. Most starters play most weeks, so the second round after you certify is usually scorable, and the Saturday after its deadline brings your first snapshot.

The second ranking comes later. The selection column compares what a player was rated over five club matches with the minutes he played over the next five, so it reads only once every club has played about ten rounds since you certified.

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

Step 10 — 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, so confirming late reveals your whole trajectory at once. Being published slowly costs you nothing.

Done when your row is on the player board, and your players appear under Players, match by match.


Your first month

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

WhenWhat happensWhat you should see
Day 0Register, enter, map, certify"certified": true, and enrolment dated now
The first round after thatYour job delivers every appearance you rateA receipt with entries accepted
That Tuesday 23:59The round's ratings freezestatus shows nothing due
The first SaturdayScoring runsNo snapshot yet — no player has a prior rating from you
The second roundDeliver again; its segments are priced on the first round's ratingsstatus empty
The Saturday after its deadlineScoring runsYour first snapshot: a skill score with an interval, and not scored yet on the selection column
After about ten roundsEnough club matches either side of a pivotThe selection column reads for the first time

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 5
400Wrong taskIt must be game_value_player
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 seasonTake ids from the appearance list; do not construct them
player did not appear in this matchNot on the appearance list for that match — often an unused substituteRate only what the list offers; check your player mapping
match not playedRated before it was playedDeliver after the match
before enrolmentThe match kicked off before you certifiedNot accepted: it could be rated knowing the result
rating is not a numberNot numeric, or not finiteSend a number, not a string, null or NaN
duplicate player in this deliveryThe same (match_id, player_id) twice in one bodySend each appearance once
frozenA different rating after the deadlineThe first rating stands; corrections had to arrive before the deadline
delivery limit reached for this roundThe round's ten deliveries are spentBatch your ratings; check status before resending

Joining mid-season

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

Ratings for matches that kicked off before you certified are refused as before enrolment. It is the rule everyone is under: a rating for a match played weeks ago could be made knowing every result since, and would not be a forecast. Since the history your first scores need is built from the day you certify, the sooner you certify, the sooner you are scored.

If your ratings predate the season, ask about a scoring exception. A rating published match by match since August, fixed before any result it is scored against, is the case it exists for. An admin can let ratings count for rounds due at or before a stated horizon, with the reason printed on every snapshot it touches and beside your name on the board. Nothing is backdated: your receipts keep the time the ratings really arrived.

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 its players to player_ids
  • Your job re-reads the player directory weekly and maps new players
  • Your job follows the appearance list with next_since, and never resumes on a time alone
  • You deliver player_ids, never names, and one rating per appearance
  • Nothing you did not rate is sent as zero
  • contract_version is the one in force, and a 409 is treated as a change to act on
  • Your job runs daily and clears the deadline by hours
  • You batch each round, and check /status before resending one
  • You keep each receipt, with its payload_sha256
  • You have certified one completed round per competition you intend to cover
  • Delivery contract — the reference for every call above, with the paging cursor and the deadline rules in full.
  • Scoring — how a delivered rating becomes a published number, and how to recompute one.
  • Overview — what is measured, and what the board does not claim.
  • Reading a leaderboard — the two rankings, the floor, and what a row on the board is telling you.