# Testing your integration A test key plays the whole flow with no money in it. One endpoint exists only here: it decides a match, so you can see a result without two people playing one. ## Deciding a match in test The test environment can end a seated match on demand. You need a `matchId` first: seat two of your own test players with `POST /partner/matches` (see [Paid play](/docs/paid-play.md)) — that call returns the `matchId` this endpoint decides. ``` POST /partner/test/matches/{matchId}/decide Authorization: Bearer pgs_test_ Content-Type: application/json { "scores": { "u_8813": 4180, "u_9001": 3960 } } ``` Name every seat by the same `playerId` you minted its session with — a missing one is refused rather than filled in. The match finishes exactly as a played one does: same finish, same seal, same rows in [the results feed](/docs/results.md), same webhook nudge. Your CI can then check that it paid the player you decided would win. > **Test keys only.** The handler cannot be reached without a token only a test key can produce. A live key gets the same `404 no such test match` as a nonexistent id, so it learns nothing about which matches do — unless you're on a deployment pinned to one environment, where it's refused earlier with `live_key_against_test`. The match must also be between test players of yours. **What it refuses with.** A match id that isn't yours, isn't a test match, or doesn't exist is `404`. A match not in a decidable state — already finished, or never seated — is `409`. A body missing a seat is `400`. These three carry a message but no `reason` code, so branch on the status. > **What a green suite covers.** The half that is yours: the seat, the feed, the webhook, and your ledger paying the player you decided would win. It does *not* exercise our scoring engine or the anti-cheat replay behind it — the score comes from you, not moves — nor a payout of ours, since a test match moves no money on either side.