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.

  • 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.