Origin API Changelog
The Origin API is in alpha and subject to change. Review the OpenAPI specification when updating an integration.
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
deadlineAttimestamp. 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 reachescompleted, leaves the stored value unchanged when an update omits the field, and rejects a deadline more than 24 hours in the future withInvalidArgument(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.comas its server and abearerAuthHTTP bearer security scheme, so a client generated from the document picks up the base URL and theAuthorization: Bearerrequirement. - Changed. OpenAPI path parameters carry the names the URLs already use. The generated
identifier.ownerSlugandidentifier.namebindings becameownerSlugandrepoNameacross 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
*_UNSPECIFIEDzero-value entries, such asRULESET_ENFORCEMENT_UNSPECIFIEDon Create Ruleset andPULL_REQUEST_REVIEW_VERDICT_UNSPECIFIEDon 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, and429responses carrying thegoogle.rpc.Statusbody, in place of the catch-alldefaultresponse alone. See Errors for the body and the full status list.
- Breaking. Reviewer webhook payloads for
pull_request.reviewer.added,pull_request.reviewer.removed, andpull_request.reviewer.rerequestedreplace thereviewer.kindandreviewer.idpair with a typed reviewer, where exactly one ofreviewer.userorreviewer.groupis present. Migration: readreviewer.user.idwhere you readreviewer.idwith areviewer.kindofuser, andreviewer.group.idwherereviewer.kindwasgroup. - Added. List Labels returns the label definitions a repository owns, ordered by name:
GET /v1/origin/repos/{ownerSlug}/{repoName}/labels. Reading labels requires the newrepository:labels:readscope. 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 newrepository:labels:writescope.nameis capped at 50 characters anddescriptionat 255,colormust be six hexadecimal characters without a leading#, and a name another label on the repository already uses is rejected withAlreadyExists(HTTP 409 Conflict). - Added. Get Label returns one repository label by name:
GET /v1/origin/repos/{ownerSlug}/{repoName}/labels/{labelName}. An unknown name returns404. - 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 withAlreadyExists(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 requiresrepository: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 requiresrepository:checks:write. A check run holds at most 100 annotations, and a batch that would exceed that is rejected withResourceExhausted(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 inpullRequests[].author.user.id,pullRequests[].author.app.id, orpullRequests[].author.serviceAccount.id;base, an exact base-branch filter that accepts a short name or a fully qualified ref;direction,descfor newest first (the default) orascfor oldest first; andsinceanduntil, inclusive RFC 3339 bounds on creation time. An author with no pull requests returns an empty list, and any other unusable value returnsInvalidArgument(HTTP 400). - Added.
pull_request.review.dismissedis delivered when a submitted review is dismissed, whether explicitly or by being superseded by a newer decision. It carries the same payload shape aspull_request.review.submittedwithreview.dismissalpopulated, and subscribing to it needsrepository:pull_requests:reviews:read. - Added. Installations name the user who installed the app.
installedBy, carrying that user's publicuser_…ID and email, is returned by Get App Installation and List App Installations and rides everyinstallation.*webhook snapshot; there it identifies the original installer and is omitted when that user record can no longer be read. The installation receipt gains aninstalledByclaim 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, carrieswebhook-event-typeofping, 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 withFailedPrecondition(HTTP 400). - Added. Error responses carry the request ID twice: an
X-Request-IDresponse header, and agoogle.rpc.RequestInfoentry indetails. Origin echoes thex-request-idyou 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
titlelonger than 256 characters, or abodylonger than 65,536 characters, withInvalidArgument(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,trueorfalse, mirroring the HTTP status:200when true,202when false. The field was previously omitted when false, so callers had to read an absent field asfalse. - 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.pushedwebhook 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
bodylonger than 65,536 characters withInvalidArgument(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}. Requiresrepository:rulesets:write. A ruleset stored on a different repository reads as an unknown ruleset, and an emptyrulesetIdis rejected withInvalidArgument(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 inGET /v1/origin/repos/_/REPO_ID. Read the ID fromidon 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 same404as 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
repositoryIdson Create Installation Access Token, and receives webhook deliveries. Until a mirror becomes a stable outbound mirror it stays read-only: onlyrepository:metadata:readandrepository:contents:readapply, and every other scope returns403on that repository, includinggit push. See Mirrored repositories.
- Breaking. The
recursivequery parameter on Get Tree is a boolean rather than a string, so onlytrueand1walk the whole tree; every other value, includingfalse,0, and a bare?recursive, lists immediate children only. Migration: sendrecursive=truewherever your integration relied on any non-emptyrecursivevalue 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
repositoryreference:GET /v1/origin/repos/{ownerSlug}/{repoName}/rulesets. Rulesets are bounded configuration, so the response is not paginated. Reading rulesets requiresrepository: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 requirerepository: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
rulesandbypassActors: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, ordisabled),kind(merge_branch,push_branch,push_tag, orpush_repository), theincludedRefNamesandexcludedRefNamespatterns that accept globs plus the~ALLand~DEFAULT_BRANCHtokens,rules, andbypassActors. Create Ruleset and Update Ruleset reject more than 64 patterns per list, 20 rules, or 15 bypass actors withInvalidArgument(HTTP 400). - Added. Merge Pull Request accepts an optional
expectedHeadSharequest field, the full commit SHA the pull request's head must match. When the head has moved, the merge is rejected withABORTED(HTTP 409 Conflict) and nothing merges; a value that is not a full commit SHA is rejected withInvalidArgument(HTTP 400). Omit it to merge whatever the current head is. - Added. Owner references carry a
typestring,teamoruser, omitted when Origin cannot resolve it. Returned wherever anowneror installationtargetappears, including Get Repo, List Repos, List App Installations, and the repository reference on check and pull request responses.
- Breaking. List Pull Request Labels returns every assigned label in one response and no longer paginates: the
pageSizeandpageTokenquery parameters and thenextPageTokenresponse field are gone. Migration: droppageSizeandpageTokenfrom the request and read the full set fromlabels. - Breaking. A pull request holds at most 100 labels, and Add Pull Request Labels and Set Pull Request Labels reject a write that would take it past that limit with
FailedPrecondition(HTTP 400). Migration: keep each pull request at or under 100 labels, removing labels before adding more. - Added. Pull requests carry a
labelsarray of the labels assigned to them, sorted by name and empty when none are assigned. Returned by List Pull Requests, Get Pull Request, Create Pull Request, Update Pull Request, and Merge Pull Request, and included on pull request lifecycle webhook payloads.
- 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. Requiresrepository: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 requiresrepository: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,coloras a six-character hex value without a leading#, and an optionaldescription. 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
403when 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: handle403on 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
defaultBranchwhen that push only creates branches and none of them is the stored default: Origin picks the created branch, ormainormasterwhen 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: handle400from 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 returns403over 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.
- Changed. Revision parameters accept the symbolic
HEADalongside a SHA, branch, or tag:shaon List Commits, Get Commit, List Commit Files, Get Git Commit, and Get Tree;refon Get Contents and Batch Get Contents; and either side ofbaseheadon Compare Commits. - Changed. Get Git Ref resolves the symbolic
HEADand returns it asref: "HEAD"with the tip commit. List Matching Git Refs and List Matching Git Refs by Path matchHEADexactly, because it does not sit underrefs/. - Changed. Removing an installation, or deleting the app, invalidates that installation's access tokens before
expiresAt. The REST API and Git over HTTPS reject a revoked token with401, so an app must be reinstalled before it can mint a working one. See Installation access token.
- Breaking. Get Contents rejects files larger than 1 MiB (decoded) with
FailedPrecondition(HTTP 400), and one oversized file fails an entire Batch Get Contents request. - Added. Installation access tokens authenticate Git over HTTPS. Use the token as the HTTP Basic password with username
x-access-tokenagainst the repositorycloneUrl. Clone, fetch, and pull requirerepository:contents:read; push requiresrepository:contents:write. See Git HTTPS authentication. - Changed.
cloneUrlcarries the GitHub-shaped root path (https://origin.cursor.com/OWNER_SLUG/REPO_NAME.git) in place of the legacy/git/path, on List Repos, Get Repo, Create Repo, List App Installation Repositories, and therepository.createdwebhook payload. Both forms clone andcloneUrlpromises no particular path shape, so a stored value keeps working. - Changed.
sizeon Get Contents and Batch Get Contents responses states the decoded content size in bytes, not the length of the base64contentstring.
- Breaking. Reviewer webhook payloads carry a stable external ID in
reviewer.id: the encoded user ID (user_…, the same format as the organization API) whenkindisuser, replacing the provider-scoped auth ID; group reviewers keep the group public ID (grp_…). Affectspull_request.reviewer.added,pull_request.reviewer.removed, andpull_request.reviewer.rerequested. Migration: match user reviewers by the encodeduser_…ID wherever your integration comparedreviewer.idagainst 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. Requiresrepository:contents:readand returns200when the sync target is satisfied or202while the sync is pending. - Added. Post-install redirects carry an
installation_receiptquery parameter: a five-minute Origin-signed JWT that identifies the installation in itssubclaim and echoes the publisher'sstateas 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
kindandidfields, completing the deprecation announced on August 5, 2026. Everyactor,author, anddismissedByfield across check, commit, and pull request responses is affected. Migration: read theuser,app, orserviceAccountvariant 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.kindandOriginActor.id. Actor identity is a discriminated union ofuser,app, andserviceAccountvariants. Migration: read the selected variant's fields instead of top-levelkindandid.