Skip to main content

Command Palette

Search for a command to run...

API

Origin API Changelog

Changes to the Origin public API, including endpoints, request and response schemas, scopes, and webhooks, grouped by day with the newest first. Each change carries one label: Breaking, Deprecated, Added, Changed, or Removed. Breaking and deprecated changes include migration guidance inline. The Origin API reference always reflects the latest synced state.

  • Breaking. Create App enforces the namespace owner's eligibility to write to Origin, the same precondition Create Repo has always carried. A request against a namespace whose user owner is not on a Pro, Pro Student, Pro+, Ultra, or Start plan, or whose team owner lacks an active paid team plan, sits on Privacy Mode (Legacy), or has Origin turned off by a team admin, returns FailedPrecondition (HTTP 400) where it previously created the app. The check reads the namespace owner's eligibility, not the calling user's. Migration: create apps only under namespaces whose owner can write to Origin, and handle FailedPrecondition wherever your integration assumed the app was created.
  • Changed. Origin allows a webhook receiver 10 seconds to answer a delivery, up from five seconds. The deadline covers DNS resolution, the connection, the TLS handshake, and the time to the response, and it applies to every attempt; an attempt that passes it counts as a transport error and is retried on the schedule Webhooks documents.
  • Breaking. Get Repo Tarball archives wrap the repository tree in a single top-level directory named {ownerSlug}-{repoName}-{shortSha}/, where shortSha is the first 7 hex characters of the resolved commit, matching the layout of GitHub's tarball endpoint. Archive entries previously sat at the root of the tar with no wrapping directory. Migration: strip one leading path component when extracting, for example tar --strip-components=1, wherever your integration read entries from the tar root.
  • Breaking. Get App requires namespace:apps:read on the app's owning namespace in place of app:settings:read, the scope announced with the endpoint in the September 12 entry. app:settings:read no longer authorizes anything and has been removed from the scope catalog; app:settings:write is unchanged and still covers Update App, Add App Signing Key, and Revoke App Signing Key. Migration: hold namespace:apps:read on the app's owning namespace wherever your integration held app:settings:read.
  • Added. List App Installation Repositories accepts filter, a case-insensitive substring match applied to repository names and owner namespaces. A single-slash owner/repo value matches each half against its corresponding field, leading and trailing whitespace is ignored, and an empty value applies no filter. A page token carries the filter it was minted under, so send the same filter when requesting subsequent pages.
  • Changed. The OpenAPI specification no longer stamps format: enum on string enum schemas. The key is not a registered OpenAPI or JSON Schema format, it duplicated the enum list beside it, and generators that mapped it to a named type emitted code that does not compile. Schema names, enum values, and the JSON on the wire are unchanged; regenerate any client built from the specification to pick up the corrected types.
  • Breaking. The repository.check_run.created and repository.check_run.completed payloads no longer carry a payload-level actor. It repeated the owning check suite's principal, which the same payload already delivers as checkSuite.actor and checkRun.actor. Migration: read checkRun.actor, which always equals the owning suite's actor, wherever your integration read the payload's top-level actor.
  • Breaking. caseInsensitive and wholeWord on Grep Contents apply only when literal is true. A regular-expression search ignores both booleans where it previously honored them, and a query of only (?i) returns InvalidArgument (HTTP 400). Migration: set literal to keep using the booleans, or for a regular-expression search write a leading (?i) and \b word bounds into query instead.
  • Breaking. The OpenAPI specification renames the Thread component schema to CommentThread. It is the response schema of Update Pull Request Thread and the type of the thread object on a pull request comment. Field names, paths, operation IDs, and the JSON on the wire are unchanged, so an integration that reads the responses directly needs no change. Migration: regenerate any client built from the specification, and rename the type wherever generated code named Thread.
  • Added. Add App Installation Repositories adds repositories to an existing installation's selection and returns the updated installation: POST /v1/origin/namespaces/{namespaceSlug}/installations/{installationId}/repos. The body takes a required repoIds array, which is unioned with the current selection; the write never changes the installation's scopes, and a request whose repositories are all already granted succeeds without changing anything. A repository outside the namespace, an installation that already covers every repository in the namespace, a suspended installation, and one that predates per-installation scopes each return FailedPrecondition (HTTP 400) and grant nothing. Requires a Cursor user credential holding namespace:installations:write and costs 5 points. A first install still needs a namespace admin's consent in the browser.
  • Added. Charged Git over HTTPS responses carry X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Used, with X-RateLimit-Resource set to git. Git meters a budget of its own, separate from the REST budget that Rate limits documents as core. An over-budget Git request returns 429 with Retry-After and X-RateLimit-Reset, and an unmetered request carries no rate-limit headers.
  • Changed. Upsert Repository Grant and Upsert Namespace Grant accept a group principal owned by the resource owner's own team, alongside the organization groups they already took. A team's own groups are grantable even when that team is not linked to an organization, while a group owned by another team still returns FailedPrecondition (HTTP 400). The Grants page covers the principal kinds.
  • Breaking. Create Repo requires namespace:repositories:create in place of namespace:new_repository:write, which no longer authorizes anything and has been removed from the scope catalog. Migration: request namespace:repositories:create on the Cursor user credential wherever your integration requested namespace:new_repository:write.
  • Added. Get Pull Request Mergeability returns whether a pull request can be merged and, when it cannot, the typed conditions blocking it: GET /v1/origin/repos/{ownerSlug}/{repoName}/pulls/{pullNumber}/mergeability. verdict is mergeable or blocked, and each entry in blockers carries a kind, a human-readable message, and the pull request in evaluatedPullRequests it belongs to, so a stacked pull request's verdict covers every pull request from the stack root through it. An optional expectedHeadSha guard returns Aborted (HTTP 409 Conflict) when the head has moved, and a mirrored repository or a stack of more than 200 pull requests returns FailedPrecondition (HTTP 400). The operation is published in preview, marked x-cursor-visibility: PREVIEW in the OpenAPI specification, so decode its responses with unknown fields and unknown enum values tolerated and treat an unrecognized verdict as blocked. Requires repository:pull_requests:read and costs 10 points.
  • Added. Grep Contents searches the text of a repository's files at a ref and returns the lines that match: POST /v1/origin/repos/{ownerSlug}/{repoName}:grep. The body takes a required query, read as a regular expression unless literal is set, plus ref, caseInsensitive, wholeWord, contextBefore and contextAfter (values above 10 are reduced to 10), filterPath, the includes and excludes glob lists (at most 20 entries each), and maxResults (default and maximum 1000). Each returned entry is one line, and the response is complete only when limitHit is false; there is no pagination. Requires repository:contents:read and costs 5 points.
  • Added. Check-run status has a fourth value, rerequested, and List Check Runs For Commit accepts it as a status filter. It marks a completed run whose re-run was asked for and the owning app has not answered yet, so treat it as pending and render it like queued. It appears on Get Check Run, List Check Runs For Suite, List Check Runs For Commit, and Rerequest Check Run. Only Origin sets it: a Post Check Run or Batch Upsert Check Runs request carrying it returns InvalidArgument (HTTP 400).
  • Added. List Pull Requests accepts sortBy, either created (creation order, the default) or updated (time of last update). direction sorts along sortBy and still defaults to desc, and a page token carries the sort it was minted under, so a token replayed under the other sort is rejected.
  • Added. List Pull Requests accepts state=merged, which lists merged pull requests only. closed keeps covering every pull request that is no longer open, merged ones included, so existing callers see the same results.
  • Changed. Rerequest Check Run sets the run's status to rerequested, superseding the September 11 note that the call never changes the run's own status or conclusion. The run's conclusion and timings keep describing the superseded attempt, so read conclusion only when status is completed. The run still reads as pending in List Check Runs For Suite and List Check Runs For Commit until the owning app answers, which also clears rerequestedAt and stores the posted status.
  • Changed. The repository.check_run.rerequested payload carries checkRun.status as rerequested rather than completed, with checkRun.conclusion and the timings still describing the superseded attempt. Migration is the same as for the endpoint: branch on checkRun.status and read checkRun.conclusion only when it is completed.

Pull requests

  • Breaking. Create Pull Request and Update Pull Request reject a base that does not name an existing branch. A commit SHA, a tag name, or a branch that does not exist returns InvalidArgument (HTTP 400) and names the fully qualified ref Origin looked for, where the same request previously created or retargeted the pull request. Such a pull request could never have its merge ref prepared, so CI never received one and the pull request could not be merged. Migration: pass a branch name, short as main or fully qualified as refs/heads/main, and retarget any existing pull request whose base is a commit SHA or a tag.

Apps

  • Added. Create App registers an app owned by a namespace: POST /v1/origin/namespaces/{namespaceSlug}/apps. The body takes a required displayName and publicKey, the PEM SPKI Ed25519 public key the app signs its JWTs with, plus optional webhookUrl, events, description, websiteUrl, installationRedirectUris, and defaultScopes. Apps are created private, and an invalid webhook URL, event type, redirect URI, or scope returns InvalidArgument (HTTP 400). Requires namespace:apps:create on a Cursor user credential and costs 10 points.
  • Added. List Namespace Apps lists the apps a namespace owns, newest first: GET /v1/origin/namespaces/{namespaceSlug}/apps. Entries carry display metadata only, id, displayName, and description; read one app's webhook configuration with Get App. Requires namespace:apps:read and costs 1 point.
  • Added. Get App returns one app's full configuration by id: GET /v1/origin/apps/{appId}. This is the publisher's management read; Get Authenticated App remains the self-read an app makes with its own JWT. Requires app:settings:read and costs 1 point.
  • Added. Update App writes an app's settings: PATCH /v1/origin/apps/{appId}. displayName, webhookUrl, description, and websiteUrl are plain fields, while events, installationRedirectUris, and defaultScopes are clean-replace wrappers that swap the whole list. Omitted fields are left unchanged, a request that sets nothing returns InvalidArgument (HTTP 400), and sending webhookUrl as an empty string disables delivery and cancels the app's pending deliveries for good. Requires app:settings:write and costs 5 points.
  • Added. Add App Signing Key registers another Ed25519 public key for an app: POST /v1/origin/apps/{appId}/signing_keys. The response carries the kid to use as the JWT key ID, the base64url-encoded SHA-256 digest of the key's SPKI DER encoding. A key that is already registered returns AlreadyExists (HTTP 409 Conflict), and a key beyond the app's active-key limit returns FailedPrecondition (HTTP 400). Requires app:settings:write and costs 5 points.
  • Added. Revoke App Signing Key retires a signing key and answers 204 No Content: DELETE /v1/origin/apps/{appId}/signing_keys/{kid}. App JWTs signed with the revoked key stop authenticating, and revoking the last active key returns FailedPrecondition (HTTP 400). Requires app:settings:write and costs 5 points.
  • Added. App responses carry namespaceSlug, the slug of the namespace that owns the app, along with description, websiteUrl, and defaultScopes. Returned by Get Authenticated App, Get App, Create App, and Update App.

Grants

  • Added. List Repository Grants lists the users, groups, and owning-team groups holding a permission granted directly on a repository: GET /v1/origin/repos/{ownerSlug}/{repoName}/grants. Permissions inherited from the repository's owner are not included, and a principal that no longer resolves is omitted, so a page can hold fewer grants than pageSize. Requires repository:settings:read and costs 1 point.
  • Added. Upsert Repository Grant sets the permission one principal holds directly on a repository: POST /v1/origin/repos/{ownerSlug}/{repoName}/grants. The body names exactly one of user, group, or teamGroup and a permission of read, write, or admin; custom returns InvalidArgument (HTTP 400), and a principal outside the owner's team or organization returns FailedPrecondition (HTTP 400). Repeating a grant the principal already holds succeeds without change. Requires repository:settings:write and costs 5 points.
  • Added. Delete Repository Grant removes the permission one principal holds directly on a repository and answers 204 No Content: DELETE /v1/origin/repos/{ownerSlug}/{repoName}/grants. Permissions inherited from the owner are unaffected, so an owning-team group falls back to its owner-level default, and removing a permission the principal does not hold directly succeeds without change. Requires repository:settings:write and costs 5 points.
  • Added. List Namespace Grants lists who has been granted access to an owner: GET /v1/origin/owners/{ownerSlug}/grants. Each grant carries the permission it confers on every repository under the owner, admin grants are listed first, and grants made on individual repositories are excluded. Requires namespace:settings:read and costs 1 point.
  • Added. Upsert Namespace Grant sets the permission one principal holds directly on an owner: POST /v1/origin/owners/{ownerSlug}/grants. permission takes PERMISSION_READ, PERMISSION_CONTRIBUTOR, PERMISSION_WRITE, or PERMISSION_ADMIN, and PERMISSION_CUSTOM returns InvalidArgument (HTTP 400). A principal outside the owning team or its organization, or a write that would leave the owner without an admin, returns FailedPrecondition (HTTP 400). Requires namespace:settings:write and costs 5 points.
  • Added. Delete Namespace Grant removes the permission one principal holds directly on an owner and answers 204 No Content: DELETE /v1/origin/owners/{ownerSlug}/grants. Per-repository grants are unaffected, and a removal that would leave the owner without an admin returns FailedPrecondition (HTTP 400). Requires namespace:settings:write and costs 5 points.

Installations

Check runs

  • Breaking. The repository.check_run.rerequested payload no longer carries a top-level rerequestedBy. The principal that asked for the re-run sits on the embedded check run as checkRun.rerequestedBy instead, superseding the September 10 note that the payload carries the requester beside the repository, suite, and run. Migration: read checkRun.rerequestedBy wherever your receiver read the payload's own rerequestedBy.
  • Added. Rerequest Check Run asks the app that reported a check run to run it again: POST /v1/origin/repos/{ownerSlug}/{repoName}/check-runs/{checkRunId}/rerequest with an empty body. The run must be completed, must carry isRerequestable, must be the current attempt for its key, and must sit on the current head of an open pull request; anything else returns FailedPrecondition (HTTP 400), and a second request while one is outstanding returns AlreadyExists (HTTP 409 Conflict). The call never changes the run's own status or conclusion. Any principal holding repository:contents:write can re-request any re-requestable run, whichever app reported it, and the call costs 5 points.
  • Added. Check runs carry rerequestedBy, the principal that asked for the re-run, present whenever rerequestedAt is set and cleared together with it. Returned by Get Check Run, List Check Runs For Suite, List Check Runs For Commit, Post Check Run, Batch Upsert Check Runs, and Rerequest Check Run.
  • Changed. rerequestedAt marks an outstanding re-request rather than a one-time stamp. Origin clears it when the owning app answers by posting a fresh run for the same head SHA and key, either a new run under a new externalId or an update of the re-requested run under the same one, after which the run can be re-requested again. This supersedes the September 10 note that a check run is re-requested at most once, so a receiver can see more than one repository.check_run.rerequested event for the same run; keep deduplicating redeliveries on the event id.
  • Changed. A re-requested check run stays in List Check Runs For Suite and List Check Runs For Commit and reads as pending, with rerequestedAt set and its superseded status and conclusion unchanged, instead of dropping out of both listings until the app answers. A required check blocks merging as a pending check rather than as a missing one. This supersedes the September 10 note that the run drops out until a new attempt arrives.

Repositories

  • Added. Update Repo writes repository settings: PATCH /v1/origin/repos/{ownerSlug}/{repoName}. The body takes optional defaultBranch, allowMergeCommit, allowSquashMerge, deleteBranchOnMerge, and visibility fields, and omitted fields are left unchanged. allowMergeCommit and allowSquashMerge must be sent together with at least one of them true; defaultBranch and deleteBranchOnMerge return FailedPrecondition (HTTP 400) on a repository that pulls from an upstream source; and a request that sets nothing returns InvalidArgument (HTTP 400). The groups apply in a fixed order rather than atomically, so a rejected group leaves the groups before it applied. Requires repository:settings:write and costs 5 points.
  • Added. Transition Repo Mirror starts a mirror-direction change and returns the job tracking it: POST /v1/origin/repos/{ownerSlug}/{repoName}/mirror:transition. The body takes a required transition of initial_to_inbound, inbound_to_outbound, or outbound_to_inbound, and the repository holds a transitioning mirror status while the job runs. A repository that is not in the transition's expected start state, or that already has an active job, returns FailedPrecondition (HTTP 400). Requires repository:mirror:write on a Cursor user credential that also administers the repository on the mirror's upstream source, and costs 10 points.
  • Added. Force Repo Mirror Cutover cuts a repository over to its upstream source without pushing divergent state back: POST /v1/origin/repos/{ownerSlug}/{repoName}/mirror:forceCutover with an empty body. The source is adopted as the source of truth as it stands, and refs that exist only on Origin are snapshotted and abandoned. It is accepted only for a repository in outbound status, or one stuck in an outbound-to-inbound transition whose active job reports requires_attention, which the forced cutover supersedes. Requires repository:mirror:write and costs 10 points.
  • Added. Detach Repo Mirror permanently disconnects a mirrored repository from its upstream source and answers 204 No Content: DELETE /v1/origin/repos/{ownerSlug}/{repoName}/mirror. The repository keeps its contents and becomes a native repository, syncing stops in both directions, and the mirror's deploy credential is deleted. Detaching an already-detached repository succeeds without effect, while a repository that never had a mirror returns FailedPrecondition (HTTP 400). Requires repository:mirror:delete and costs 5 points.
  • Added. Get Mirror Transition Job returns one transition job by id: GET /v1/origin/repos/{ownerSlug}/{repoName}/mirror/transition-jobs/{jobId}. A job reports its transition, a status of queued, running, succeeded, failed_rolled_back, requires_attention, or superseded, an attemptCount, and lastErrorCode and lastErrorMessage once it has failed. Its phase string is display detail that gains new values as the transition process evolves, so poll status for completion instead of matching on phase. Requires repository:metadata:read and costs 1 point.
  • Added. Get Active Mirror Transition Job returns the repository's in-progress transition job and its most recent terminal one: GET /v1/origin/repos/{ownerSlug}/{repoName}/mirror/transition-jobs:active. Both activeJob and lastJob are optional, so a repository that has never transitioned returns an empty object, and polling until activeJob disappears and then reading lastJob is what distinguishes a transition that finished from one that never ran. Requires repository:metadata:read and costs 1 point.
  • Changed. The mirror-state endpoint references moved to the Origin Migration API. Their HTTP contracts are unchanged, and the previous Origin API anchors link to the new reference.
  • Added. Merge Pull Request accepts an optional mergeMethod of merge or squash, choosing whether the pull request lands as a merge commit or as a single squash commit. A method the repository does not allow is rejected with FailedPrecondition (HTTP 400), and any other value, rebase included, with InvalidArgument (HTTP 400). Omit it to keep the previous behavior: a merge commit when the repository allows one, otherwise a squash, and a squash when the base branch requires linear history.
  • Added. Repository payloads carry visibility, which is internal or private, along with the allowMergeCommit, allowSquashMerge, and deleteBranchOnMerge booleans. All four are read-only and are returned by Get Repo, Create Repo, List Repos, and List App Installation Repositories.
  • Added. Check runs carry isRerequestable, the reporting app's declaration that the run can be run again, and rerequestedAt, the timestamp of the re-request. Send isRerequestable on Post Check Run and Batch Upsert Check Runs; both fields come back there and on Get Check Run, List Check Runs For Suite, and List Check Runs For Commit. Declaring a run re-requestable commits your app to answering each re-request by posting a new run for the same head SHA and key.
  • Added. repository.check_run.rerequested is delivered when a completed check run is re-requested, and it reaches only the app that owns the run rather than every subscriber to the repository. Its payload carries the repository, the check suite, the stamped check run, and rerequestedBy, and it carries no pull request context, so resolve the pull request from checkRun.sha. Subscribing takes repository:checks:read. A check run is re-requested at most once, so deduplicate redeliveries on the event id.
  • Added. Every webhook payload schema in the OpenAPI specification carries an x-origin-webhook-events extension naming the events it is delivered with, plus a curated sample payload as its schema example, and the new Event payloads reference documents each payload's fields and sample payload, generated from those schemas in the same layout as the endpoint reference.
  • Changed. A re-requested check run drops out of List Check Runs For Suite and List Check Runs For Commit until the app that owns it posts a new attempt or refreshes the existing one with a newer externalUpdatedAt. A required check therefore reads as missing and blocks merging while the re-request is outstanding. Read the excluded run by its own id with Get Check Run.
  • Breaking. An inline anchor whose line range runs past the end of the file is rejected with InvalidArgument (HTTP 400) on Create Pull Request Comment and Create Pull Request Review. The range is still not restricted to the diff's hunks, and it is checked against the file as it exists on the anchored side, which left reads at the base commit and right at the head; the error names the file's line count. On a review, one out-of-range anchor fails the whole request and publishes nothing. Migration: bound inline.startLine and inline.endLine to the anchored side's line count before writing, reading it from Get Contents when the anchor sits outside the diff's hunks.
  • Added. Create Git Ref creates a branch at an existing commit: POST /v1/origin/repos/{ownerSlug}/{repoName}/git/refs. It takes ref as refs/heads/<branch> or heads/<branch> and sha as the full hex SHA of a commit in the repository; tags and other reference namespaces return InvalidArgument (HTTP 400). Creating a branch that already points at sha returns the existing reference, and a branch that exists at another commit returns AlreadyExists (HTTP 409 Conflict). Requires repository:contents:write and costs 5 points.
  • Added. Create Commit From Files commits inline file changes to a branch and advances it: POST /v1/origin/repos/{ownerSlug}/{repoName}/git/commits:createFromFiles. Each files[] entry sets exactly one of content (with encoding utf-8 or base64 and mode file, executable, or symlink) and delete, and expectedHeadSha must match the branch tip, which becomes the new commit's parent. The response returns sha, treeSha, and previousHeadSha. One request carries at most 1,000 file changes, 8 MiB per file, and 32 MiB of content in total. Requires repository:contents:write and costs 10 points.
  • Changed. Webhook delivery retries a failed send seven times instead of six, and the first retry lands 5 seconds after the failure rather than 30 seconds. The full ladder is 5 seconds, 30 seconds, 1 minute, 2 minutes, 4 minutes, and 8 minutes, so a receiver that is down the whole time sees one more POST over roughly the same 16-minute window. Deduplicate the extra attempt on webhook-id the same way you deduplicate the rest.
  • Breaking. App metadata no longer carries slug. It is gone from the Get Authenticated App response, from every app actor that check, pull request, review, and comment operations return (actor.app, author.app, and dismissal.dismissedBy.app), from the app object on the five installation.* webhook payloads, and from the Ping Webhook payload, superseding the September 2 note that app actors carry displayName alongside id and slug. An app actor was previously guaranteed to carry slug; it now carries id and the optional displayName. Migration: address apps by id and label them with displayName wherever your integration read slug.
  • Added. List Pull Request Comments accepts an optional threadIds query parameter that restricts the listing to comments in those threads, which is how you read one thread without paging a pull request's whole comment history. Duplicates are ignored, so the limit of 20 applies to distinct IDs, and a longer list or an empty ID returns InvalidArgument (HTTP 400). Page tokens embed the set they were minted under, so restart pagination when the filter changes.
  • Changed. The author filter on List Pull Requests also accepts the exact email address of a user, matched case-insensitively, alongside the user_…, app_…, and sa_… actor IDs it already took. An email that resolves to no single user returns an empty list rather than an error, and an email previously returned InvalidArgument (HTTP 400). Apps and service accounts have no email identity, so only user authors can be selected that way, and actor IDs remain the identity these responses return.
  • Added. List Check Runs For Commit accepts optional checkName and status query parameters. checkName matches a check run's name exactly, and status takes queued, in_progress, or completed; any other value returns InvalidArgument (HTTP 400). Both filters apply after the latest-attempt collapse, so a run matches on its latest attempt's status and a filter never resurfaces a superseded attempt. Page tokens embed the filters they were minted under, so restart pagination when a filter changes.
  • Added. List Pull Request Comments accepts optional since and until query parameters, inclusive bounds on comment creation time as RFC 3339 timestamps such as 2026-08-01T00:00:00Z. A malformed timestamp returns InvalidArgument (HTTP 400). Page tokens embed the bounds they were minted under, so restart pagination when a bound changes. Track new comments with since instead of re-paging a pull request's whole comment history.
  • Changed. An operation whose required scopes come with the credential rather than from an installation grant marks its x-origin-scopes extension ambient: true in the published OpenAPI specification. Nine operations carry the flag, among them Get Authenticated App, Create Installation Access Token, and List App Installation Repositories. The scope strings stay in the extension so 403 responses still name them, and request handling is unchanged; read the flag to tell an operation you only have to authenticate for from one that needs a scope approved at installation.
  • Breaking. List Check Suites For Commit, List Check Runs For Commit, and List Check Runs For Suite return only the latest attempt of each check and omit superseded attempts, matching what the merge gate and the product CI views already showed. A suite collapses to its latest attempt per reporting actor and suite key, and a run to its latest attempt per run key within a suite, so a failed run and its successful retry no longer both appear. totalSize and page tokens count the collapsed set. Migration: read a superseded attempt by its own id through Get Check Run or Get Check Suite, which still address every stored attempt.
  • Added. Create Pull Request Comment accepts a file anchor that opens a comment thread on a whole file in the pull request version's diff. It carries file.path alone: Origin derives the side from the file's change kind, the base version for a deleted file and the head version otherwise, and returns it on thread.side. Send the deleted path for a deletion and the head path for every other change; a path outside the diff or a renamed file's pre-rename source path returns InvalidArgument (HTTP 400). file, inline, and threadId are mutually exclusive. Create Pull Request Review takes the same anchor as comments[].file.
  • Added. Public user actors carry displayName and handle alongside id and email. displayName is the account's first and last name joined with a space, the same name the product renders, and is omitted when the account has no name. handle is the claimed profile handle without the @ prefix, present only while that profile is publicly visible. Both appear wherever a user actor does, including pull request and comment authors, check run and suite actors, review dismissals, requested reviewers, an installation's installedBy, and the matching webhook payloads. The installation receipt carries displayName and never handle.
  • Added. Public app actors carry the app's registered displayName alongside id and slug, and the app object on the five installation.* webhook payloads carries it too. It is omitted when the app cannot be resolved and on Cursor's first-party managed actor.
  • Changed. Requesting a :write scope also grants the matching :read scope, so an installation asking for repository:labels:write is granted repository:labels:read with it. This applies when an app is installed, when an installation is previewed, and when an installation access token attenuates its scopes, and an existing write-only credential now permits the matching read. Read scopes still never grant writes.
  • Added. repository.deleted delivers when a repository is deleted, whether through a product delete of a native or outbound repository or by stopping the sync on an inbound mirror. The payload carries a repository reference and deletedAt rather than a snapshot, because a deleted repository no longer resolves through the API. Subscribing requires repository:metadata:read. Unlike repository.pushed, this event is delivered for repositories mirrored from GitHub, since stopping the sync deletes only the Cursor-side repository and GitHub sends nothing for it. A repeated delete of an already-deleted repository emits nothing.
  • Added. repository.metadata.updated delivers when a repository's default branch changes, covering settings and API writes, an inbound mirror following an upstream rename, and first-push trunk reconciliation. The payload carries the full post-write repository snapshot with no delta and no updating actor, so compare successive snapshots or refetch the repository to see what moved. Subscribing requires repository:metadata:read.
  • Added. Requested-reviewer users carry an email alongside id. It appears on List Pull Request Requested Reviewers and Request Pull Request Reviewers, and on the reviewer.user entry of the pull_request.reviewer.added, pull_request.reviewer.removed, and pull_request.reviewer.rerequested webhooks. The value is the account email address, and it is empty when the account has none. These surfaces previously identified a user by id alone.
  • Changed. REST responses carry fields that sit at their default value instead of dropping them, so a false boolean, a 0 number, an empty string, and an empty array are present in every response body. A non-draft pull request from Get Pull Request reports draft as false rather than omitting it, and an empty list reports [] rather than nothing at all. Fields the contract marks optional, such as submitted_at and dismissal, stay absent when unset. Read the value itself wherever your integration treated a missing key as the default. This matches how webhook payloads have always serialized.
  • Changed. Each operation in the published OpenAPI specification carries a unique operationId. Where one operation answers two URL shapes, the second shape takes a _2 suffix: OriginService_GetRepoTarball_2 for GET …/tarball/{ref} and OriginService_ListMatchingGitRefs_2 for GET …/git/matching-refs. Both URL shapes and their request handling are unchanged, so regenerate any client built from the specification to pick up the renamed methods.
  • Changed. installation.updated also delivers when the owner namespace is renamed, once for each installation the namespace still holds. The event carries the new namespace slug along with that installation's current scopes and repository selection.
  • Changed. Every operation in the published OpenAPI specification carries an x-origin-scopes extension that names the scope the operation requires and the credentials it accepts. scopes holds the required scope, and tokenTypes holds the accepted credential kinds: app for an app JWT, installation for an installation access token, and user for a user credential. A credential kind the operation rejects is absent from tokenTypes, and Get Rate Limit is the one operation that requires no scope. The extension also replaced the scope sentences that Create Label, Update Label, and Delete Label carried in their descriptions. Authorization is unchanged; the extension publishes the scopes Origin already enforced.
  • Added. List Pull Request Requested Reviewers returns the users and groups whose review is outstanding on a pull request: GET /v1/origin/repos/{ownerSlug}/{repoName}/pulls/{pullNumber}/requested_reviewers. A direct request clears when that user submits a review, and a group request clears when any current member of the group submits, while an unsubmitted draft review leaves the request pending. Reviewers come back as ids, and reading them requires repository:pull_requests:reviews:read.
  • Added. Request Pull Request Reviewers requests reviews from users and groups and returns the reviewers it requested: POST /v1/origin/repos/{ownerSlug}/{repoName}/pulls/{pullNumber}/requested_reviewers. Identify each reviewer by public user_… id, email, grp_… id, or group slug; display names do not resolve, an unknown or ambiguous identifier returns InvalidArgument (HTTP 400), and a reviewer who is not a candidate for the repository returns PermissionDenied (HTTP 403). Requesting an already-requested reviewer bumps the request, so a reviewer who had submitted a review reappears as pending. Requires repository:pull_requests:reviews:write.
  • Added. Remove Pull Request Requested Reviewers drops outstanding review requests and returns 204 with an empty body: DELETE /v1/origin/repos/{ownerSlug}/{repoName}/pulls/{pullNumber}/requested_reviewers. Removing a reviewer who is not currently requested is a no-op, and a stable public id still resolves after that reviewer leaves the repository's candidate list, so a stale request can be cleared. Requires repository:pull_requests:reviews:write.
  • Added. Update Pull Request Thread resolves or reopens a pull request comment thread and returns its updated state: PATCH /v1/origin/repos/{ownerSlug}/{repoName}/pulls/threads/{threadId}. Send resolved as true to resolve and false to reopen. Both directions are idempotent, replying to a resolved thread does not reopen it, and a thread stored on another repository returns 404. Requires repository:pull_requests:reviews:write.
  • Added. Pull request comments carry their full thread in place of a bare thread id. thread gained the filed-against version with its head and base SHAs, the path, side, startLine, and endLine of the thread's diff anchor, resolvedAt, and the thread's own createdAt and updatedAt. Returned by List Pull Request Comments, Get Pull Request Comment, and Update Pull Request Comment. thread.id is unchanged, so grouping comments by it keeps working.
  • Added. Create Pull Request Comment accepts an inline anchor, made of path, side, startLine, and an optional endLine, that opens a line-anchored thread on a pull request version's diff, plus a versionNumber naming the version to file against that defaults to the latest at call time. The path must be part of that version's diff on a side the file has content on, any line of a changed file anchors rather than only lines inside a diff hunk, and an invalid anchor returns InvalidArgument (HTTP 400) instead of falling back to a general-discussion comment. inline and threadId are mutually exclusive, as are threadId and versionNumber.
  • Added. Create Pull Request Review accepts a comments array, at most 50 per request, that publishes a review together with its comments in one atomic call. Each entry carries a body plus the same targets as Create Pull Request Comment: an inline anchor on the reviewed version's diff, a threadId reply, or neither for a new general-discussion thread. Every anchor is validated before anything is written, so a single bad anchor fails the whole request with InvalidArgument (HTTP 400) and publishes nothing. The operation carries no idempotency key, so read List Pull Request Reviews before retrying an ambiguous failure. A request without comments behaves as it did.
  • Added. pull_request.comment.created carries the thread's diff anchor on the comment that opened the thread, so a receiver can materialize the thread without a follow-up read. comment.thread holds the filed-against version, path, side, startLine, and endLine; a reply carries comment.thread.id alone, and resolution state stays out of the event. Comments filed with a review through Create Pull Request Review emit nothing until the review submits, and then each one emits its own event.
  • Added. Get Repo Tarball downloads a gzip-compressed tar of a repository tree: GET /v1/origin/repos/{ownerSlug}/{repoName}/tarball/{ref}. The first request for a resolved commit streams application/gzip as the response body; later requests for the same commit return 302 with a signed download URL in Location, valid for 15 minutes. Archive entries sit at the root of the tar with no wrapping directory, an empty repository returns ABORTED (HTTP 409 Conflict), and downloading an archive requires repository:contents:read.
  • Added. List Comparison Files lists the files a comparison changed, the diff of head against the merge base of base and head: GET /v1/origin/repos/{ownerSlug}/{repoName}/compare/{basehead}/files. Results are paginated, 30 files per page by default and at most 100, and each file carries the shape List Commit Files returns. An identical or behind comparison returns an empty list, unrelated histories return 404, and a comparison whose commits move mid-pagination rejects the page token with InvalidArgument (HTTP 400) so listing restarts from the first page. Reading comparison files requires repository:contents:read.
  • Added. The signing key endpoint sends Cache-Control: public, max-age=600, stale-if-error=600. Reuse a cached JWKS for 10 minutes, then refresh; when a refresh fails, keep the last good keys for at most another 10 minutes before failing verification. Refresh on a signature no active key verifies so a retired key ID drops out.
  • Changed. A check run still in_progress when its deadlineAt passes completes with a timed_out conclusion and delivers repository.check_run.completed, superseding the August 27 note that a deadline does not change a run's status. Expiry runs as a periodic sweep rather than a per-run timer, so a run can sit past its deadline briefly. A queued run never expires, nor does a run carrying no deadlineAt, and Origin leaves the run's externalUpdatedAt in place so a later completion from your provider can overwrite the timed_out conclusion.
  • Changed. repository.pushed is not delivered for a repository Origin mirrors from GitHub. GitHub owns those pushes and sends its own push webhooks, so the Origin delivery duplicated them. Pushes to native Origin repositories and to outbound mirrors are delivered unchanged, and mirror state affects no other event.
  • Changed. Create Pull Request rejects a head with no history in common with base with InvalidArgument (HTTP 400) and creates nothing, in place of the 404 the underlying comparison surfaced.
  • Changed. A push that leaves an open pull request's head with no history in common with its base closes the pull request and delivers pull_request.closed. A later related push does not reopen it.
  • Changed. Each operation in the OpenAPI specification documents the response codes that operation can return, in place of a uniform 400, 401, 403, and 429 on every operation: 404 on every parameterized path, 409 wherever a handler reports a conflict, 202 on Batch Redeliver Webhook Deliveries and Sync Mirror, and shorter sets on Get Rate Limit and Get Authenticated App. The Status schema describes the error envelope Origin returns, including that a 404 never distinguishes a missing resource from an unreachable one, and every operation carries a request and response example. Request handling is unchanged; regenerate any client built from the spec to pick up the new response models.
  • Added. Check runs accept and return an optional deadlineAt timestamp. Send it in the run body on Post Check Run or Batch Upsert Check Runs, and read it back on Get Check Run, List Check Runs For Suite, and List Check Runs For Commit. Origin clears the deadline once the run reaches completed, leaves the stored value unchanged when an update omits the field, and rejects a deadline more than 24 hours in the future with InvalidArgument (HTTP 400) rather than clamping it. A deadline does not change the run's status when it passes.
  • Changed. The published OpenAPI specification declares https://api.cursor.com as its server and a bearerAuth HTTP bearer security scheme, so a client generated from the document picks up the base URL and the Authorization: Bearer requirement.
  • Changed. OpenAPI path parameters carry the names the URLs already use. The generated identifier.ownerSlug and identifier.name bindings became ownerSlug and repoName across all 55 repository-scoped operations, which lets standard OpenAPI generators consume the document. Request URLs and request behavior are unchanged; regenerate any client built from the spec to pick up the new parameter names.
  • Changed. Published enums no longer list their *_UNSPECIFIED zero-value entries, such as RULESET_ENFORCEMENT_UNSPECIFIED on Create Ruleset and PULL_REQUEST_REVIEW_VERDICT_UNSPECIFIED on Create Pull Request Review. Origin never accepted or returned those values, so requests and responses are unchanged.
  • Changed. Every operation in the spec documents 400, 401, 403, and 429 responses carrying the google.rpc.Status body, in place of the catch-all default response alone. See Errors for the body and the full status list.
  • Breaking. Reviewer webhook payloads for pull_request.reviewer.added, pull_request.reviewer.removed, and pull_request.reviewer.rerequested replace the reviewer.kind and reviewer.id pair with a typed reviewer, where exactly one of reviewer.user or reviewer.group is present. Migration: read reviewer.user.id where you read reviewer.id with a reviewer.kind of user, and reviewer.group.id where reviewer.kind was group.
  • Added. List Labels returns the label definitions a repository owns, ordered by name: GET /v1/origin/repos/{ownerSlug}/{repoName}/labels. Reading labels requires the new repository:labels:read scope. Results are paginated, 30 labels per page by default and at most 100.
  • Added. Create Label defines a label on a repository and returns it: POST /v1/origin/repos/{ownerSlug}/{repoName}/labels. Every label write requires the new repository:labels:write scope. name is capped at 50 characters and description at 255, color must be six hexadecimal characters without a leading #, and a name another label on the repository already uses is rejected with AlreadyExists (HTTP 409 Conflict).
  • Added. Get Label returns one repository label by name: GET /v1/origin/repos/{ownerSlug}/{repoName}/labels/{labelName}. An unknown name returns 404.
  • Added. Delete Label deletes a repository label by name and returns 204: DELETE /v1/origin/repos/{ownerSlug}/{repoName}/labels/{labelName}. Deleting a label also removes it from every pull request it was assigned to.
  • Added. Update Label changes a label's name, color, or description, addressing it by its current name: PATCH /v1/origin/repos/{ownerSlug}/{repoName}/labels/{labelName}. Omitted fields are left unchanged, and renaming to a name another label already uses is rejected with AlreadyExists (HTTP 409 Conflict).
  • Added. List Check Run Annotations returns a check run's annotations in ascending ID order, which is also creation order: GET /v1/origin/repos/{ownerSlug}/{repoName}/check-runs/{checkRunId}/annotations. Reading them requires repository:checks:read. Results are paginated, 30 annotations per page by default and at most 100.
  • Added. Create Check Run Annotations appends between 1 and 25 annotations to a check run in one atomic batch and returns them: POST /v1/origin/repos/{ownerSlug}/{repoName}/check-runs/{checkRunId}/annotations. Appending requires repository:checks:write. A check run holds at most 100 annotations, and a batch that would exceed that is rejected with ResourceExhausted (HTTP 429) without writing anything. The operation is append-only and not idempotent, so a retry after an ambiguous failure can append duplicates.
  • Added. List Pull Requests takes five more query parameters: author, a public actor ID exactly as the response returns it in pullRequests[].author.user.id, pullRequests[].author.app.id, or pullRequests[].author.serviceAccount.id; base, an exact base-branch filter that accepts a short name or a fully qualified ref; direction, desc for newest first (the default) or asc for oldest first; and since and until, inclusive RFC 3339 bounds on creation time. An author with no pull requests returns an empty list, and any other unusable value returns InvalidArgument (HTTP 400).
  • Added. pull_request.review.dismissed is delivered when a submitted review is dismissed, whether explicitly or by being superseded by a newer decision. It carries the same payload shape as pull_request.review.submitted with review.dismissal populated, and subscribing to it needs repository:pull_requests:reviews:read.
  • Added. Installations name the user who installed the app. installedBy, carrying that user's public user_… ID and email, is returned by Get App Installation and List App Installations and rides every installation.* webhook snapshot; there it identifies the original installer and is omitted when that user record can no longer be read. The installation receipt gains an installedBy claim naming the user who performed that install or re-consent, so after a re-consent the two can differ.
  • Added. Ping Webhook sends a test delivery to your app's configured webhook URL and reports what the receiver answered: POST /v1/origin/app/webhook/pings. The delivery is signed like a production one, carries webhook-event-type of ping, and belongs to no installation. Origin sends it once with no retries, and it never appears in List Webhook Deliveries. An app with no webhook URL configured is rejected with FailedPrecondition (HTTP 400).
  • Added. Error responses carry the request ID twice: an X-Request-ID response header, and a google.rpc.RequestInfo entry in details. Origin echoes the x-request-id you sent or generates one when you send none, and includes the entry even when the message is an opaque internal error. See Errors.
  • Changed. Create Pull Request and Update Pull Request reject a title longer than 256 characters, or a body longer than 65,536 characters, with InvalidArgument (HTTP 400). Values past those lengths previously failed with an internal error. Both limits count Unicode code points, so an astral character such as an emoji counts once.
  • Changed. Sync Mirror responses always carry synced, true or false, mirroring the HTTP status: 200 when true, 202 when false. The field was previously omitted when false, so callers had to read an absent field as false.
  • Changed. Unmatched paths under /v1/origin, and requests that use the wrong method on a known path, return the documented error envelope rather than a generic router body. The message names the method and path and never echoes the query string.
  • Changed. Merging a pull request delivers a repository.pushed webhook for the base ref the merge advances. Origin performs that push itself, so the event names no pusher. Base-ref updates from a merge were previously not delivered.
  • Changed. Create Pull Request Comment and Update Pull Request Comment reject a body longer than 65,536 characters with InvalidArgument (HTTP 400). A body past that length previously failed with an internal error. The limit counts Unicode code points, so an astral character such as an emoji counts once.
  • Added. Delete Ruleset deletes a repository ruleset by its stable Origin ID and returns 204: DELETE /v1/origin/repos/{ownerSlug}/{repoName}/rulesets/{rulesetId}. Requires repository:rulesets:write. A ruleset stored on a different repository reads as an unknown ruleset, and an empty rulesetId is rejected with InvalidArgument (HTTP 400).
  • Added. Every repository-scoped endpoint addresses a repository by its stable ID as well as by owner and name: send _ as the owner slug and the ID as the repository name, as in GET /v1/origin/repos/_/REPO_ID. Read the ID from id on Get Repo. The ID survives a rename but grants nothing on its own, so your app needs the same scope on the resolved repository, and an ID it cannot reach returns the same 404 as an ID that does not exist. Create Repo takes an owner slug alone and rejects _.
  • Changed. Apps reach mirrored repositories. A mirror can be selected into an installation, appears in List App Installation Repositories and in the installation webhook payload repository arrays, can be named in repositoryIds on Create Installation Access Token, and receives webhook deliveries. Until a mirror becomes a stable outbound mirror it stays read-only: only repository:metadata:read and repository:contents:read apply, and every other scope returns 403 on that repository, including git push. See Mirrored repositories.
  • Breaking. The recursive query parameter on Get Tree is a boolean rather than a string, so only true and 1 walk the whole tree; every other value, including false, 0, and a bare ?recursive, lists immediate children only. Migration: send recursive=true wherever your integration relied on any non-empty recursive value enabling recursion.
  • Breaking. Pull request lifecycle webhook payloads omit the pull request's assigned labels, superseding the field announced on August 20, 2026. REST responses still carry it. Migration: read labels from Get Pull Request or List Pull Requests instead of the webhook snapshot.
  • Added. List Rulesets returns every ruleset configured on a repository plus one shared repository reference: GET /v1/origin/repos/{ownerSlug}/{repoName}/rulesets. Rulesets are bounded configuration, so the response is not paginated. Reading rulesets requires repository:rulesets:read.
  • Added. Create Ruleset stores a new ruleset and returns it with the IDs Origin assigns to each rule and bypass actor: POST /v1/origin/repos/{ownerSlug}/{repoName}/rulesets. Both ruleset write endpoints require repository:rulesets:write.
  • Added. Get Ruleset returns a single ruleset by its stable Origin ID: GET /v1/origin/repos/{ownerSlug}/{repoName}/rulesets/{rulesetId}.
  • Added. Update Ruleset replaces a ruleset's configuration in full, including its rules and bypassActors: PUT /v1/origin/repos/{ownerSlug}/{repoName}/rulesets/{rulesetId}. Send every rule and bypass actor you want to keep, because the stored entries are replaced rather than merged.
  • Added. Rulesets carry id, name, description, enforcement (active, evaluate, or disabled), kind (merge_branch, push_branch, push_tag, or push_repository), the includedRefNames and excludedRefNames patterns that accept globs plus the ~ALL and ~DEFAULT_BRANCH tokens, rules, and bypassActors. Create Ruleset and Update Ruleset reject more than 64 patterns per list, 20 rules, or 15 bypass actors with InvalidArgument (HTTP 400).
  • Added. Merge Pull Request accepts an optional expectedHeadSha request field, the full commit SHA the pull request's head must match. When the head has moved, the merge is rejected with ABORTED (HTTP 409 Conflict) and nothing merges; a value that is not a full commit SHA is rejected with InvalidArgument (HTTP 400). Omit it to merge whatever the current head is.
  • Added. Owner references carry a type string, team or user, omitted when Origin cannot resolve it. Returned wherever an owner or installation target appears, including Get Repo, List Repos, List App Installations, and the repository reference on check and pull request responses.
  • Added. List Pull Request Labels returns the labels assigned to a pull request, ordered by name: GET /v1/origin/repos/{ownerSlug}/{repoName}/pulls/{pullNumber}/labels. Requires repository:pull_requests:read. Results are paginated, 30 labels per page by default, and at most 100 labels per page.
  • Added. Add Pull Request Labels assigns existing repository labels to a pull request and leaves the labels already on it in place: POST /v1/origin/repos/{ownerSlug}/{repoName}/pulls/{pullNumber}/labels. Every label write endpoint requires repository:pull_requests:write.
  • Added. Set Pull Request Labels replaces every label on a pull request with the names you send, and an empty list clears them: PUT /v1/origin/repos/{ownerSlug}/{repoName}/pulls/{pullNumber}/labels.
  • Added. Remove Pull Request Label removes one label by name and returns the labels left on the pull request: DELETE /v1/origin/repos/{ownerSlug}/{repoName}/pulls/{pullNumber}/labels/{labelName}.
  • Added. Remove All Pull Request Labels clears every label from a pull request and returns 204: DELETE /v1/origin/repos/{ownerSlug}/{repoName}/pulls/{pullNumber}/labels.
  • Added. Label entries carry id, name, color as a six-character hex value without a leading #, and an optional description. Returned by every pull request label endpoint.
  • Changed. The app JWT rate limit budget rose from 600 to 6,000 points per minute, and Create Installation Access Token charges 1 point instead of 5, so an app can mint roughly 100 installation tokens per second.
  • Changed. Owner eligibility for Create Repo and pushes over Git HTTPS admits the Pro Student and Start plans alongside Pro, Pro+, and Ultra. Team-owner requirements are unchanged.
  • Changed. Owner slugs and repository names in repository paths resolve case-insensitively, and responses return the stored casing rather than the casing you sent. Create Repo rejects a name that differs only in case from one the owner already has, so compare repository names case-insensitively.
  • Breaking. Git over HTTPS rejects a push with 403 when the repository's owner is not eligible to write to Origin. A user owner must be on a Pro, Pro+, or Ultra plan, and a team owner must have an active paid team plan, must not be on Privacy Mode (Legacy), and must not have Origin turned off by a team admin. Clone, fetch, and pull are unaffected. Migration: handle 403 on push as an owner-eligibility failure that a retry cannot clear, and confirm the owner's plan before pushing on its behalf.
  • Changed. The first push to a repo created through Create Repo retargets defaultBranch when that push only creates branches and none of them is the stored default: Origin picks the created branch, or main or master when the push creates several and one of those names is among them. Read the current value from Get Repo.
  • Breaking. Create Repo rejects a request whose owner is not eligible to write to Origin, returning FailedPrecondition (HTTP 400). A user owner must be on a Pro, Pro+, or Ultra plan, and a team owner must have an active paid team plan, must not be on Privacy Mode (Legacy), and must not have Origin turned off by a team admin. Migration: handle 400 from Create Repo as an owner-eligibility failure that a retry cannot clear, and confirm the owner's plan before creating repositories on its behalf.
  • Breaking. Apps lost access to repositories that Origin mirrors in from GitHub. Those repositories no longer appear in List App Installation Repositories, Create Installation Access Token rejects them in repositoryIds, and a request that names one returns 403 over both the REST API and Git over HTTPS. Migration: discover repositories from List App Installation Repositories instead of a stored repository list, and read a GitHub-sourced repository from GitHub rather than the Origin API.
  • Breaking. Origin stopped sending webhooks for repositories it mirrors in from GitHub, and installation event payloads dropped those repositories from their selected repository arrays and repositoriesCount. Migration: source events for a GitHub-sourced repository from GitHub, and treat an installation payload's repository array as the set your app can reach.
  • Breaking. Reviewer webhook payloads carry a stable external ID in reviewer.id: the encoded user ID (user_…, the same format as the organization API) when kind is user, replacing the provider-scoped auth ID; group reviewers keep the group public ID (grp_…). Affects pull_request.reviewer.added, pull_request.reviewer.removed, and pull_request.reviewer.rerequested. Migration: match user reviewers by the encoded user_… ID wherever your integration compared reviewer.id against stored auth IDs.
  • Added. Apps can hold up to 10 active Ed25519 signing keys, and app JWT verification accepts a token signed with any active key.
  • Added. Sync Mirror synchronizes one ref of a mirrored repository from its upstream source: POST /v1/origin/repos/{ownerSlug}/{repoName}:syncMirror. Requires repository:contents:read and returns 200 when the sync target is satisfied or 202 while the sync is pending.
  • Added. Post-install redirects carry an installation_receipt query parameter: a five-minute Origin-signed JWT that identifies the installation in its sub claim and echoes the publisher's state as a claim. Verify it against the published JWKS before trusting the callback. See Installation receipt.
  • Removed. Origin actor objects no longer include the top-level kind and id fields, completing the deprecation announced on August 5, 2026. Every actor, author, and dismissedBy field across check, commit, and pull request responses is affected. Migration: read the user, app, or serviceAccount variant set on the actor.
  • Added. Get Rate Limit returns the authenticated principal's shared per-minute point budget without consuming points: GET /v1/origin/rate_limit. See Rate limits.
  • Deprecated. OriginActor.kind and OriginActor.id. Actor identity is a discriminated union of user, app, and serviceAccount variants. Migration: read the selected variant's fields instead of top-level kind and id.