API / stack-origin-pull-requests-via-api

API

Stack Origin Pull Requests via the API

Associate a pull request with a stack parent using parentPullRequest on Create and Update Pull Request, read the stack object on pull responses, and list a stack with stackId on List Pull Requests. Official reference: Origin API → Create / Update / List Pull Requests. Changelog: September 22, 2026.

Origin is in Early Beta and subject to change. Authenticate with an installation access token (oit_…) or a user access token that carries repository:pull_requests:write for create/update and repository:pull_requests:read for list. Availability: Early Beta per the API overview.

Breaking (2026-09-22): Create Pull Request no longer accepts parentPullNumber. A request that still sends it returns InvalidArgument (HTTP 400) naming parent_pull_number. Send parentPullRequest with a number member instead.

The edit is an association only: no branch is rewritten. base is retargeted only when you send base too. On Update, parentPullRequest applies after base, so an explicit parent wins over the one a base change would derive.

Cost: 5 points for create/update; 1 point for list.

Create with a stack parent

POST https://api.cursor.com/v1/origin/repos/{ownerSlug}/{repoName}/pulls

Field Required Meaning
parentPullRequest no Selector naming the stack parent. Exactly one of number or id. Do not send clear on create.
curl --request POST \
  --url 'https://api.cursor.com/v1/origin/repos/OWNER_SLUG/REPO_NAME/pulls' \
  --header 'Authorization: Bearer YOUR_ORIGIN_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
  "title": "Follow-up telemetry polish",
  "head": "telemetry-polish",
  "base": "main",
  "parentPullRequest": {
    "number": "17"
  }
}'

An empty selector, more than one member, or clear on create returns InvalidArgument (HTTP 400). Pull request number values are JSON strings.

Update or clear the parent

PATCH https://api.cursor.com/v1/origin/repos/{ownerSlug}/{repoName}/pulls/{pullNumber}

curl --request PATCH \
  --url 'https://api.cursor.com/v1/origin/repos/OWNER_SLUG/REPO_NAME/pulls/18' \
  --header 'Authorization: Bearer YOUR_ORIGIN_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
  "parentPullRequest": {
    "clear": true
  }
}'

clear: false, an empty selector, or more than one member returns InvalidArgument (HTTP 400).

Read stack on responses

List, Get, Create, Update, and Merge Pull Request responses (and every pull_request.* webhook payload) carry a stack object with the stack's id and the parentPullRequest this change is stacked on. stack is absent when the pull request is not part of a stack. The root of a stack carries no parentPullRequest. A delivered stack reflects topology as of that event.

List one stack

GET https://api.cursor.com/v1/origin/repos/{ownerSlug}/{repoName}/pulls?stackId=STACK_ID

Pass the stack id from stack.id. Members come back in the requested sort order, not stack order — rebuild the stack from each member's stack.parentPullRequest. state still defaults to open, so pass state=all for the whole stack. A well-formed id that names no stack in the repository returns an empty list. Any other value returns InvalidArgument (HTTP 400).

curl --request GET \
  --url 'https://api.cursor.com/v1/origin/repos/OWNER_SLUG/REPO_NAME/pulls?stackId=STACK_ID&state=all' \
  --header 'Authorization: Bearer YOUR_ORIGIN_TOKEN'

Related

Pitfalls

  • Keep sending parentPullNumber and Create fails loudly with 400 — migrate to parentPullRequest.number.
  • Listing a stack without state=all hides closed and merged members.