
Read Origin Check Run Upsert Outcome via the API
Every Post Check Run and Batch Upsert Check Runs response now pairs each stored run with an outcome so you can tell a create from an update from a no-op. Official reference: Origin API → Check runs / Ordering writes. Changelog: September 22, 2026.
Origin is in Early Beta and subject to change. Authenticate with an installation access token (oit_…) that carries repository:checks:write. Availability: Early Beta per the API overview.
A stale post still returns HTTP 200 with the stored suite and run — not the posted values — and does not move updatedAt. Only outcome (or each results[].outcome in a batch) tells you what happened.
outcome |
Meaning |
|---|---|
created |
No run existed for (externalId, key) in the suite; one was created |
updated |
An existing run was replaced with the posted values |
unchanged |
Posted values, externalUpdatedAt included, equal the stored run; nothing written |
ignored_stale |
Post ignored as stale; checkRun is the stored run, not the posted values |
Treat an unrecognized value as "the stored run is in the response; whether it was written is unknown."
Post Check Run
POST https://api.cursor.com/v1/origin/repos/{ownerSlug}/{repoName}/check-runs returns checkSuite, checkRun, and top-level outcome.
curl --request POST \
--url 'https://api.cursor.com/v1/origin/repos/OWNER_SLUG/REPO_NAME/check-runs' \
--header 'Authorization: Bearer oit_...' \
--header 'Content-Type: application/json' \
--data '{
"headSha": "9a41f0c3d2b8e7f6a5c4d3e2f1b0a9c8d7e6f5a4",
"checkSuite": { "key": "ci-8842", "name": "CI" },
"checkRun": {
"key": "ci-8842-unit-tests",
"name": "unit-tests",
"status": "completed",
"conclusion": "success",
"externalUpdatedAt": "2026-08-02T14:44:30Z",
"externalId": "run-8842"
}
}'
Read outcome next to checkRun on every response.
Batch Upsert Check Runs
POST …/check-runs:batchUpsert returns results[], one entry per posted run in request order. Each entry pairs checkRun with its own outcome. A stale run does not fail the batch.
Deprecated: top-level checkRuns[] is still populated with the same stored runs in the same order, but it carries no outcomes. Migrate to results[].
Annotation message fields may contain Markdown (rendered on the pull request Checks tab and inline card). rawDetails stays plain text.
Related
- Single upsert body: Upsert an Origin Check Run via the API.
- Batch body: Batch Upsert Origin Check Runs via the API.
Pitfalls
- Do not branch on
updatedAtto detect a no-op — it stays put forunchangedandignored_stale. - Keep sending increasing
externalUpdatedAtvalues so retries do not land asignored_stale.