checks:write can report results on a commit in a repository the installation covers. Use checks for tests, security scans, code review or any other work whose result a customer may require before merging.
What you need
- Register your plugin with
checks:writeand have the customer accept it. Writing checks alone does not need contents access, but addcontents:read(orcontents:write) if your service reads code or receives ref or trail webhooks. - Mint an access token scoped to the repository, with
{"checks": "write"}. - Take the repository’s
idand processing-primaryapi_base_urlfrom the repository list. Use the full commit SHA, 40 or 64 characters.
Report a result
A suite groups one kind of work, such as a security scan. You can report its result alone, or include individual runs for its parts. Send one suite per request:branch is the branch name without refs/heads/. Keep key stable and readable: customers see it on the trail and use it when they require checks. The suite’s name is stored metadata, not its current display label. Give external_id a new value for each attempt, including a rerun on the same commit. It can be up to 255 bytes.
details_url is optional. It must use HTTPS and contain no credentials. Link to the result in your service, where the customer can read logs or take action.
A write applies in full or not at all. Retrying the same request is safe. A 200 response identifies the suite and returns an outcome for each run: created, updated, unchanged or ignored_stale. It does not return the suite’s state; read it back to confirm that.
Keep it current
Reportqueued when you accept work, in_progress when it starts, and completed when it ends. Use these values for both suites and runs:
action_required counts as passing. If an approval must block a merge, keep the suite pending instead.
When you send suite state, include both status and external_updated_at, plus conclusion when completed. Set the timestamp to when the state changed in your service, not when you sent the request. Timestamps must be RFC 3339 with a zero UTC offset; nonzero offsets are refused with 400. Entire stores millisecond precision.
Suites and runs can also carry started_at and completed_at. The same rules apply to them, and completed_at can’t be before started_at.
Older state updates are ignored. An identical retry leaves the result unchanged. An update with the same timestamp can change values, but reopening completed work as queued or in_progress needs a newer timestamp. A timestamp more than 60 seconds in the future is refused.
Within an attempt, cancellation cannot replace a passing result. Across suite attempts, a cancelled attempt does not replace the newest non-cancelled attempt if that attempt passes. Keep the same external_id when updating an attempt; use a new one when you start the work again.
Include individual runs
You don’t need a run for every internal step. When separate results help the customer, add them tocheck_runs:
key and attempt external_id. Two runs in one request can’t share both. A request can include up to 5,000 runs. An output title can be up to 255 characters and its Markdown summary up to 65,535 bytes. Keep reports small and link to full logs.
The suite’s reported state decides its result, even when runs have different results. Keep it pending while more work can start, and report its final result when the work ends. This also lets you report a failure before any run starts.
To update runs without changing suite state, omit all suite state fields. Runs omitted from a request keep their stored results. A suite that has never reported its own state takes its result from its current runs; it must have at least one run. Don’t create a run with the suite’s key just to represent the suite’s result.
Deadlines
A run can includedeadline_at, in UTC and at most 24 hours ahead. After that time, the expiry sweep completes an in_progress run as timed_out. Queued runs and runs without a deadline don’t time out automatically. Omitting a deadline from a later nonterminal update preserves it; completing the run clears it.
Suites have no deadline. A run timing out doesn’t change a suite that reports its own state, so report the suite’s final result yourself.
Read your results
checks:write token. These endpoints return your plugin’s current results on the commit, without earlier attempts, in one page. Omit suite_key to read runs from all your suites. Run attempts are ordered by their update time; a suite attempt’s ordering also accounts for updates to its runs.
Each check-writing plugin has its own gate. See the plugin gate rules for how your reports affect merging, and Review and require checks for the customer’s settings. If the gate has no required names, it doesn’t wait for a suite that hasn’t reported yet. Send queued promptly if your work should block merging while it runs.
Mirrored repositories use the same API. Entire shows your results on its trails; it does not create a separate upstream check for each suite.
Errors
For token errors, see Access repositories. For a Go implementation, see Report check runs with the SDK.