Origin API Changelog
The Origin API is in Early Beta 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.
- 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 handleFailedPreconditionwherever 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}/, whereshortShais 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 exampletar --strip-components=1, wherever your integration read entries from the tar root. - Breaking. Get App requires
namespace:apps:readon the app's owning namespace in place ofapp:settings:read, the scope announced with the endpoint in the September 12 entry.app:settings:readno longer authorizes anything and has been removed from the scope catalog;app:settings:writeis unchanged and still covers Update App, Add App Signing Key, and Revoke App Signing Key. Migration: holdnamespace:apps:readon the app's owning namespace wherever your integration heldapp:settings:read. - Added. List App Installation Repositories accepts
filter, a case-insensitive substring match applied to repository names and owner namespaces. A single-slashowner/repovalue 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: enumon string enum schemas. The key is not a registered OpenAPI or JSON Schema format, it duplicated theenumlist 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.createdandrepository.check_run.completedpayloads no longer carry a payload-levelactor. It repeated the owning check suite's principal, which the same payload already delivers ascheckSuite.actorandcheckRun.actor. Migration: readcheckRun.actor, which always equals the owning suite'sactor, wherever your integration read the payload's top-levelactor. - Breaking.
caseInsensitiveandwholeWordon Grep Contents apply only whenliteralis true. A regular-expression search ignores both booleans where it previously honored them, and aqueryof only(?i)returnsInvalidArgument(HTTP 400). Migration: setliteralto keep using the booleans, or for a regular-expression search write a leading(?i)and\bword bounds intoqueryinstead. - Breaking. The OpenAPI specification renames the
Threadcomponent schema toCommentThread. It is the response schema of Update Pull Request Thread and the type of thethreadobject 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 namedThread. - 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 requiredrepoIdsarray, 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 returnFailedPrecondition(HTTP 400) and grant nothing. Requires a Cursor user credential holdingnamespace:installations:writeand 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, andX-RateLimit-Used, withX-RateLimit-Resourceset togit. Git meters a budget of its own, separate from the REST budget that Rate limits documents ascore. An over-budget Git request returns429withRetry-AfterandX-RateLimit-Reset, and an unmetered request carries no rate-limit headers. - Changed. Upsert Repository Grant and Upsert Namespace Grant accept a
groupprincipal 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 returnsFailedPrecondition(HTTP 400). The Grants page covers the principal kinds.
- Breaking. Create Repo requires
namespace:repositories:createin place ofnamespace:new_repository:write, which no longer authorizes anything and has been removed from the scope catalog. Migration: requestnamespace:repositories:createon the Cursor user credential wherever your integration requestednamespace: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.verdictismergeableorblocked, and each entry inblockerscarries akind, a human-readablemessage, and the pull request inevaluatedPullRequestsit belongs to, so a stacked pull request's verdict covers every pull request from the stack root through it. An optionalexpectedHeadShaguard returnsAborted(HTTP 409 Conflict) when the head has moved, and a mirrored repository or a stack of more than 200 pull requests returnsFailedPrecondition(HTTP 400). The operation is published in preview, markedx-cursor-visibility: PREVIEWin the OpenAPI specification, so decode its responses with unknown fields and unknown enum values tolerated and treat an unrecognizedverdictasblocked. Requiresrepository:pull_requests:readand 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 requiredquery, read as a regular expression unlessliteralis set, plusref,caseInsensitive,wholeWord,contextBeforeandcontextAfter(values above 10 are reduced to 10),filterPath, theincludesandexcludesglob lists (at most 20 entries each), andmaxResults(default and maximum 1000). Each returned entry is one line, and the response is complete only whenlimitHitis false; there is no pagination. Requiresrepository:contents:readand costs 5 points. - Added. Check-run
statushas a fourth value,rerequested, and List Check Runs For Commit accepts it as astatusfilter. 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 likequeued. 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 returnsInvalidArgument(HTTP 400). - Added. List Pull Requests accepts
sortBy, eithercreated(creation order, the default) orupdated(time of last update).directionsorts alongsortByand still defaults todesc, 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.closedkeeps 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
statustorerequested, superseding the September 11 note that the call never changes the run's ownstatusorconclusion. The run'sconclusionand timings keep describing the superseded attempt, so readconclusiononly whenstatusiscompleted. 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 clearsrerequestedAtand stores the posted status. - Changed. The
repository.check_run.rerequestedpayload carriescheckRun.statusasrerequestedrather thancompleted, withcheckRun.conclusionand the timings still describing the superseded attempt. Migration is the same as for the endpoint: branch oncheckRun.statusand readcheckRun.conclusiononly when it iscompleted.
Pull requests
- Breaking. Create Pull Request and Update Pull Request reject a
basethat does not name an existing branch. A commit SHA, a tag name, or a branch that does not exist returnsInvalidArgument(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 asmainor fully qualified asrefs/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 requireddisplayNameandpublicKey, the PEM SPKI Ed25519 public key the app signs its JWTs with, plus optionalwebhookUrl,events,description,websiteUrl,installationRedirectUris, anddefaultScopes. Apps are created private, and an invalid webhook URL, event type, redirect URI, or scope returnsInvalidArgument(HTTP 400). Requiresnamespace:apps:createon 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, anddescription; read one app's webhook configuration with Get App. Requiresnamespace:apps:readand 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. Requiresapp:settings:readand costs 1 point. - Added. Update App writes an app's settings:
PATCH /v1/origin/apps/{appId}.displayName,webhookUrl,description, andwebsiteUrlare plain fields, whileevents,installationRedirectUris, anddefaultScopesare clean-replace wrappers that swap the whole list. Omitted fields are left unchanged, a request that sets nothing returnsInvalidArgument(HTTP 400), and sendingwebhookUrlas an empty string disables delivery and cancels the app's pending deliveries for good. Requiresapp:settings:writeand 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 thekidto 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 returnsAlreadyExists(HTTP 409 Conflict), and a key beyond the app's active-key limit returnsFailedPrecondition(HTTP 400). Requiresapp:settings:writeand 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 returnsFailedPrecondition(HTTP 400). Requiresapp:settings:writeand costs 5 points. - Added. App responses carry
namespaceSlug, the slug of the namespace that owns the app, along withdescription,websiteUrl, anddefaultScopes. 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 thanpageSize. Requiresrepository:settings:readand 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 ofuser,group, orteamGroupand apermissionofread,write, oradmin;customreturnsInvalidArgument(HTTP 400), and a principal outside the owner's team or organization returnsFailedPrecondition(HTTP 400). Repeating a grant the principal already holds succeeds without change. Requiresrepository:settings:writeand 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. Requiresrepository:settings:writeand 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. Requiresnamespace:settings:readand costs 1 point. - Added. Upsert Namespace Grant sets the permission one principal holds directly on an owner:
POST /v1/origin/owners/{ownerSlug}/grants.permissiontakesPERMISSION_READ,PERMISSION_CONTRIBUTOR,PERMISSION_WRITE, orPERMISSION_ADMIN, andPERMISSION_CUSTOMreturnsInvalidArgument(HTTP 400). A principal outside the owning team or its organization, or a write that would leave the owner without an admin, returnsFailedPrecondition(HTTP 400). Requiresnamespace:settings:writeand 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 returnsFailedPrecondition(HTTP 400). Requiresnamespace:settings:writeand costs 5 points.
Installations
- Added. Installations carry
suspendedAt, set while the installation is suspended and omitted while it is active, anddeletedAt, carried only on theinstallation.deletedwebhook snapshot. Returned by Get App Installation and List App Installations. - Added. The five
installation.*payloads carryinstallation.appId, the same value as the payload's ownapp.id, andinstallation.updatedAtoninstallation.createdandinstallation.updated. Every field of an installation as Get App Installation returns it is present on the snapshot under the same name and type, so one decoder reads both.
Check runs
- Breaking. The
repository.check_run.rerequestedpayload no longer carries a top-levelrerequestedBy. The principal that asked for the re-run sits on the embedded check run ascheckRun.rerequestedByinstead, superseding the September 10 note that the payload carries the requester beside the repository, suite, and run. Migration: readcheckRun.rerequestedBywherever your receiver read the payload's ownrerequestedBy. - 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}/rerequestwith an empty body. The run must becompleted, must carryisRerequestable, must be the current attempt for itskey, and must sit on the current head of an open pull request; anything else returnsFailedPrecondition(HTTP 400), and a second request while one is outstanding returnsAlreadyExists(HTTP 409 Conflict). The call never changes the run's ownstatusorconclusion. Any principal holdingrepository:contents:writecan 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 wheneverrerequestedAtis 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.
rerequestedAtmarks 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 andkey, either a new run under a newexternalIdor 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 onerepository.check_run.rerequestedevent 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
rerequestedAtset and its supersededstatusandconclusionunchanged, 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 optionaldefaultBranch,allowMergeCommit,allowSquashMerge,deleteBranchOnMerge, andvisibilityfields, and omitted fields are left unchanged.allowMergeCommitandallowSquashMergemust be sent together with at least one of themtrue;defaultBranchanddeleteBranchOnMergereturnFailedPrecondition(HTTP 400) on a repository that pulls from an upstream source; and a request that sets nothing returnsInvalidArgument(HTTP 400). The groups apply in a fixed order rather than atomically, so a rejected group leaves the groups before it applied. Requiresrepository:settings:writeand 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 requiredtransitionofinitial_to_inbound,inbound_to_outbound, oroutbound_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, returnsFailedPrecondition(HTTP 400). Requiresrepository:mirror:writeon 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:forceCutoverwith 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 inoutboundstatus, or one stuck in an outbound-to-inbound transition whose active job reportsrequires_attention, which the forced cutover supersedes. Requiresrepository:mirror:writeand 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 returnsFailedPrecondition(HTTP 400). Requiresrepository:mirror:deleteand 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 itstransition, astatusofqueued,running,succeeded,failed_rolled_back,requires_attention, orsuperseded, anattemptCount, andlastErrorCodeandlastErrorMessageonce it has failed. Itsphasestring is display detail that gains new values as the transition process evolves, so pollstatusfor completion instead of matching onphase. Requiresrepository:metadata:readand 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. BothactiveJobandlastJobare optional, so a repository that has never transitioned returns an empty object, and polling untilactiveJobdisappears and then readinglastJobis what distinguishes a transition that finished from one that never ran. Requiresrepository:metadata:readand 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
mergeMethodofmergeorsquash, 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 withFailedPrecondition(HTTP 400), and any other value,rebaseincluded, withInvalidArgument(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 isinternalorprivate, along with theallowMergeCommit,allowSquashMerge, anddeleteBranchOnMergebooleans. 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, andrerequestedAt, the timestamp of the re-request. SendisRerequestableon 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 andkey. - Added.
repository.check_run.rerequestedis 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, andrerequestedBy, and it carries no pull request context, so resolve the pull request fromcheckRun.sha. Subscribing takesrepository: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-eventsextension naming the events it is delivered with, plus a curated sample payload as its schemaexample, 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
inlineanchor whose line range runs past the end of the file is rejected withInvalidArgument(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, whichleftreads at the base commit andrightat 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: boundinline.startLineandinline.endLineto 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 takesrefasrefs/heads/<branch>orheads/<branch>andshaas the full hex SHA of a commit in the repository; tags and other reference namespaces returnInvalidArgument(HTTP 400). Creating a branch that already points atshareturns the existing reference, and a branch that exists at another commit returnsAlreadyExists(HTTP 409 Conflict). Requiresrepository:contents:writeand 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. Eachfiles[]entry sets exactly one ofcontent(withencodingutf-8orbase64andmodefile,executable, orsymlink) anddelete, andexpectedHeadShamust match the branch tip, which becomes the new commit's parent. The response returnssha,treeSha, andpreviousHeadSha. One request carries at most 1,000 file changes, 8 MiB per file, and 32 MiB of content in total. Requiresrepository:contents:writeand 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
POSTover roughly the same 16-minute window. Deduplicate the extra attempt onwebhook-idthe 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, anddismissal.dismissedBy.app), from theappobject on the fiveinstallation.*webhook payloads, and from the Ping Webhook payload, superseding the September 2 note that app actors carrydisplayNamealongsideidandslug. An app actor was previously guaranteed to carryslug; it now carriesidand the optionaldisplayName. Migration: address apps byidand label them withdisplayNamewherever your integration readslug. - Added. List Pull Request Comments accepts an optional
threadIdsquery 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 returnsInvalidArgument(HTTP 400). Page tokens embed the set they were minted under, so restart pagination when the filter changes. - Changed. The
authorfilter on List Pull Requests also accepts the exact email address of a user, matched case-insensitively, alongside theuser_…,app_…, andsa_…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 returnedInvalidArgument(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
checkNameandstatusquery parameters.checkNamematches a check run'snameexactly, andstatustakesqueued,in_progress, orcompleted; any other value returnsInvalidArgument(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
sinceanduntilquery parameters, inclusive bounds on comment creation time as RFC 3339 timestamps such as2026-08-01T00:00:00Z. A malformed timestamp returnsInvalidArgument(HTTP 400). Page tokens embed the bounds they were minted under, so restart pagination when a bound changes. Track new comments withsinceinstead 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-scopesextensionambient: truein 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 so403responses 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.
totalSizeand 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
fileanchor that opens a comment thread on a whole file in the pull request version's diff. It carriesfile.pathalone: 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 onthread.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 returnsInvalidArgument(HTTP 400).file,inline, andthreadIdare mutually exclusive. Create Pull Request Review takes the same anchor ascomments[].file. - Added. Public user actors carry
displayNameandhandlealongsideidandemail.displayNameis 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.handleis 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'sinstalledBy, and the matching webhook payloads. The installation receipt carriesdisplayNameand neverhandle. - Added. Public app actors carry the app's registered
displayNamealongsideidandslug, and theappobject on the fiveinstallation.*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
:writescope also grants the matching:readscope, so an installation asking forrepository:labels:writeis grantedrepository:labels:readwith 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.deleteddelivers 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 arepositoryreference anddeletedAtrather than a snapshot, because a deleted repository no longer resolves through the API. Subscribing requiresrepository:metadata:read. Unlikerepository.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.updateddelivers 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-writerepositorysnapshot with no delta and no updating actor, so compare successive snapshots or refetch the repository to see what moved. Subscribing requiresrepository:metadata:read. - Added. Requested-reviewer users carry an
emailalongsideid. It appears on List Pull Request Requested Reviewers and Request Pull Request Reviewers, and on thereviewer.userentry of thepull_request.reviewer.added,pull_request.reviewer.removed, andpull_request.reviewer.rerequestedwebhooks. 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
falseboolean, a0number, an empty string, and an empty array are present in every response body. A non-draft pull request from Get Pull Request reportsdraftasfalserather than omitting it, and an empty list reports[]rather than nothing at all. Fields the contract marks optional, such assubmitted_atanddismissal, 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_2suffix:OriginService_GetRepoTarball_2forGET …/tarball/{ref}andOriginService_ListMatchingGitRefs_2forGET …/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.updatedalso 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-scopesextension that names the scope the operation requires and the credentials it accepts.scopesholds the required scope, andtokenTypesholds the accepted credential kinds:appfor an app JWT,installationfor an installation access token, anduserfor a user credential. A credential kind the operation rejects is absent fromtokenTypes, 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 requiresrepository: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 publicuser_…id, email,grp_…id, or group slug; display names do not resolve, an unknown or ambiguous identifier returnsInvalidArgument(HTTP 400), and a reviewer who is not a candidate for the repository returnsPermissionDenied(HTTP 403). Requesting an already-requested reviewer bumps the request, so a reviewer who had submitted a review reappears as pending. Requiresrepository:pull_requests:reviews:write. - Added. Remove Pull Request Requested Reviewers drops outstanding review requests and returns
204with 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. Requiresrepository: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}. Sendresolvedastrueto resolve andfalseto reopen. Both directions are idempotent, replying to a resolved thread does not reopen it, and a thread stored on another repository returns404. Requiresrepository:pull_requests:reviews:write. - Added. Pull request comments carry their full thread in place of a bare thread id.
threadgained the filed-againstversionwith its head and base SHAs, thepath,side,startLine, andendLineof the thread's diff anchor,resolvedAt, and the thread's owncreatedAtandupdatedAt. Returned by List Pull Request Comments, Get Pull Request Comment, and Update Pull Request Comment.thread.idis unchanged, so grouping comments by it keeps working. - Added. Create Pull Request Comment accepts an
inlineanchor, made ofpath,side,startLine, and an optionalendLine, that opens a line-anchored thread on a pull request version's diff, plus aversionNumbernaming the version to file against that defaults to the latest at call time. Thepathmust 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 returnsInvalidArgument(HTTP 400) instead of falling back to a general-discussion comment.inlineandthreadIdare mutually exclusive, as arethreadIdandversionNumber. - Added. Create Pull Request Review accepts a
commentsarray, at most 50 per request, that publishes a review together with its comments in one atomic call. Each entry carries abodyplus the same targets as Create Pull Request Comment: aninlineanchor on the reviewed version's diff, athreadIdreply, 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 withInvalidArgument(HTTP 400) and publishes nothing. The operation carries no idempotency key, so read List Pull Request Reviews before retrying an ambiguous failure. A request withoutcommentsbehaves as it did. - Added.
pull_request.comment.createdcarries 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.threadholds the filed-againstversion,path,side,startLine, andendLine; a reply carriescomment.thread.idalone, 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 streamsapplication/gzipas the response body; later requests for the same commit return302with a signed download URL inLocation, valid for 15 minutes. Archive entries sit at the root of the tar with no wrapping directory, an empty repository returnsABORTED(HTTP 409 Conflict), and downloading an archive requiresrepository:contents:read. - Added. List Comparison Files lists the files a comparison changed, the diff of
headagainst the merge base ofbaseandhead: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. Anidenticalorbehindcomparison returns an empty list, unrelated histories return404, and a comparison whose commits move mid-pagination rejects the page token withInvalidArgument(HTTP 400) so listing restarts from the first page. Reading comparison files requiresrepository: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_progresswhen itsdeadlineAtpasses completes with atimed_outconclusion and deliversrepository.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. Aqueuedrun never expires, nor does a run carrying nodeadlineAt, and Origin leaves the run'sexternalUpdatedAtin place so a later completion from your provider can overwrite thetimed_outconclusion. - Changed.
repository.pushedis 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
headwith no history in common withbasewithInvalidArgument(HTTP 400) and creates nothing, in place of the404the 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, and429on every operation:404on every parameterized path,409wherever a handler reports a conflict,202on Batch Redeliver Webhook Deliveries and Sync Mirror, and shorter sets on Get Rate Limit and Get Authenticated App. TheStatusschema describes the error envelope Origin returns, including that a404never 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
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.