markdown · 7252 bytes Raw Blame History

Pull requests

Pull requests live per repo. They share the issues row for title/body/state/timeline; this surface exposes the PR-specific shape (refs, oids, mergeability, merge state). Reviews and review comments live in a sibling batch that ships later.

Pull request shape

{
  "id": 19,
  "number": 1,
  "title": "wire up foo",
  "body": "first cut",
  "state": "open",
  "draft": false,
  "base_ref": "trunk",
  "head_ref": "feature",
  "base_oid": "abc…",
  "head_oid": "def…",
  "mergeable": true,
  "mergeable_state": "clean",
  "merged": false,
  "author_id": 42,
  "created_at": "2026-05-12T05:00:00Z",
  "updated_at": "2026-05-12T05:00:00Z"
}

mergeable is omitted while the worker hasn't computed it yet (treat absence as "unknown"). mergeable_state mirrors GitHub's vocabulary (clean, dirty, blocked, unknown, unstable, has_hooks, etc. — depending on what the worker recorded).

When merged is true, merge_commit_sha, merge_method, and merged_at are populated.

List pull requests

GET /api/v1/repos/{owner}/{repo}/pulls

Required scope: repo:read. Paginated; ?per_page= (≤100) and ?page= apply, with the standard Link: header.

Optional ?state=open|closed|all filter (defaults to all); optional ?draft=true|false filter.

Get a single pull request

GET /api/v1/repos/{owner}/{repo}/pulls/{number}

Required scope: repo:read. 404 when the number refers to an issue (use the issues surface) or when the caller can't see the repo.

Create a pull request

POST /api/v1/repos/{owner}/{repo}/pulls

Required scope: repo:write. Policy: ActionPullCreate.

{
  "title": "wire up foo",
  "body": "first cut",
  "base": "trunk",
  "head": "feature",
  "draft": false
}
Field Type Notes
title string Required, 1–256 chars.
body string Optional markdown body, ≤65535 chars.
base string Required, branch name on the target repo.
head string Required, must differ from base.
draft bool Open as draft; flip to ready via PATCH.

Returns 201 with the PR envelope. 422 when head or base don't resolve, when they're equal, or when no commits are ahead of base.

Update a pull request

PATCH /api/v1/repos/{owner}/{repo}/pulls/{number}

Required scope: repo:write. Send only the fields you want to change.

{
  "title": "renamed",
  "body": "updated body",
  "state": "closed",
  "draft": false
}

Permission rules:

  • Title / body — PR author OR a repo collaborator with write access. Other callers 403.
  • StateActionPullClose on the repo.
  • Draft — flipping truefalse (mark ready) is author-only. falsetrue is not supported (422).

List commits in a pull request

GET /api/v1/repos/{owner}/{repo}/pulls/{number}/commits

Required scope: repo:read. Returns the commit set ahead of base in order, populated by the synchronize worker after open.

List files changed by a pull request

GET /api/v1/repos/{owner}/{repo}/pulls/{number}/files

Required scope: repo:read. Each entry carries path, status (added/modified/removed/renamed), additions, deletions, and changes. old_path is set on renames.

Merge a pull request

PUT /api/v1/repos/{owner}/{repo}/pulls/{number}/merge

Required scope: repo:write. Policy: ActionPullMerge.

{
  "commit_title": "Optional override",
  "commit_message": "Optional body",
  "merge_method": "merge",
  "sha": "<head_oid>"
}
Field Type Notes
commit_title string Subject override; falls back to "<title> (#<number>)".
commit_message string Body for the merge commit. Ignored on rebase.
merge_method string "merge", "squash", "rebase" — must be enabled on the repo. Defaults to the repo's default merge method.
sha string Optional head_oid guard; 409 on mismatch.

Returns 200 with the freshly-loaded PR (state now closed, merged true). 409 when the PR is already merged/closed or when mergeable_state isn't clean. 422 when the requested merge method is disabled on the repo or when no commits are ahead of base. 503 if another merge is in flight.

Reviews

PR reviews bundle a verdict (approve, request_changes, or comment) with optional body and any draft inline comments the caller had pending on this PR.

List reviews

GET /api/v1/repos/{owner}/{repo}/pulls/{number}/reviews

Required scope: repo:read. Returns submitted reviews in creation order.

Submit a review

POST /api/v1/repos/{owner}/{repo}/pulls/{number}/reviews

Required scope: repo:write. Policy: ActionPullReview — reviewers must be repo collaborators with at least write access.

{ "event": "APPROVE", "body": "looks good to me" }

event is one of APPROVE, REQUEST_CHANGES, COMMENT (lowercase accepted too). Submitting APPROVE as the PR author returns 403. Submitting attaches every pending inline comment the caller authored on this PR.

Inline review comments

List

GET /api/v1/repos/{owner}/{repo}/pulls/{number}/comments

Required scope: repo:read. Returns one entry per inline comment with file_path, side, original_commit_sha, original_line, original_position, optional current_position (absent → outdated), pending, resolved, and threading via in_reply_to_id.

Add

POST /api/v1/repos/{owner}/{repo}/pulls/{number}/comments

Required scope: repo:write. Policy: ActionPullReview.

{
  "body": "nit: unused import",
  "file_path": "foo.txt",
  "side": "right",
  "original_commit_sha": "abc123",
  "original_line": 12,
  "original_position": 8,
  "current_position": 8,
  "pending": true
}

pending=true files a draft that's attached to the next review the caller submits. in_reply_to_id threads under an existing comment and inherits its diff anchor.

Requested reviewers

List active

GET /api/v1/repos/{owner}/{repo}/pulls/{number}/requested_reviewers

Required scope: repo:read. Returns active and historical review requests with dismissed_at / satisfied_by_review_id set when applicable.

Request a reviewer

POST /api/v1/repos/{owner}/{repo}/pulls/{number}/requested_reviewers

Required scope: repo:write. Policy: ActionPullReview. Body:

{ "user_id": 42 }

or equivalently { "username": "bob" }. 409 when the user is already an active pending reviewer; 422 on unknown user.

Dismiss a request

DELETE /api/v1/repos/{owner}/{repo}/pulls/{number}/requested_reviewers

Required scope: repo:write. Same body. Returns 204; 404 when there is no active request for that user.

Not yet shipped

  • PUT /pulls/{n}/update-branch
  • PUT /pulls/{n}/auto-merge
View source
1 # Pull requests
2
3 Pull requests live per repo. They share the `issues` row for
4 title/body/state/timeline; this surface exposes the PR-specific
5 shape (refs, oids, mergeability, merge state). Reviews and review
6 comments live in a sibling batch that ships later.
7
8 ## Pull request shape
9
10 ```json
11 {
12 "id": 19,
13 "number": 1,
14 "title": "wire up foo",
15 "body": "first cut",
16 "state": "open",
17 "draft": false,
18 "base_ref": "trunk",
19 "head_ref": "feature",
20 "base_oid": "abc…",
21 "head_oid": "def…",
22 "mergeable": true,
23 "mergeable_state": "clean",
24 "merged": false,
25 "author_id": 42,
26 "created_at": "2026-05-12T05:00:00Z",
27 "updated_at": "2026-05-12T05:00:00Z"
28 }
29 ```
30
31 `mergeable` is omitted while the worker hasn't computed it yet
32 (treat absence as "unknown"). `mergeable_state` mirrors GitHub's
33 vocabulary (`clean`, `dirty`, `blocked`, `unknown`, `unstable`,
34 `has_hooks`, etc. — depending on what the worker recorded).
35
36 When `merged` is true, `merge_commit_sha`, `merge_method`, and
37 `merged_at` are populated.
38
39 ## List pull requests
40
41 ```
42 GET /api/v1/repos/{owner}/{repo}/pulls
43 ```
44
45 Required scope: `repo:read`. Paginated; `?per_page=` (≤100) and
46 `?page=` apply, with the standard `Link:` header.
47
48 Optional `?state=open|closed|all` filter (defaults to all);
49 optional `?draft=true|false` filter.
50
51 ## Get a single pull request
52
53 ```
54 GET /api/v1/repos/{owner}/{repo}/pulls/{number}
55 ```
56
57 Required scope: `repo:read`. `404` when the number refers to an
58 issue (use the issues surface) or when the caller can't see the
59 repo.
60
61 ## Create a pull request
62
63 ```
64 POST /api/v1/repos/{owner}/{repo}/pulls
65 ```
66
67 Required scope: `repo:write`. Policy: `ActionPullCreate`.
68
69 ```json
70 {
71 "title": "wire up foo",
72 "body": "first cut",
73 "base": "trunk",
74 "head": "feature",
75 "draft": false
76 }
77 ```
78
79 | Field | Type | Notes |
80 |---------|--------|----------------------------------------------------|
81 | `title` | string | Required, 1–256 chars. |
82 | `body` | string | Optional markdown body, ≤65535 chars. |
83 | `base` | string | Required, branch name on the target repo. |
84 | `head` | string | Required, must differ from `base`. |
85 | `draft` | bool | Open as draft; flip to ready via PATCH. |
86
87 Returns `201` with the PR envelope. `422` when `head` or `base`
88 don't resolve, when they're equal, or when no commits are ahead
89 of `base`.
90
91 ## Update a pull request
92
93 ```
94 PATCH /api/v1/repos/{owner}/{repo}/pulls/{number}
95 ```
96
97 Required scope: `repo:write`. Send only the fields you want to
98 change.
99
100 ```json
101 {
102 "title": "renamed",
103 "body": "updated body",
104 "state": "closed",
105 "draft": false
106 }
107 ```
108
109 Permission rules:
110
111 - **Title / body** — PR author OR a repo collaborator with write
112 access. Other callers `403`.
113 - **State** — `ActionPullClose` on the repo.
114 - **Draft** — flipping `true``false` (mark ready) is
115 author-only. `false``true` is not supported (`422`).
116
117 ## List commits in a pull request
118
119 ```
120 GET /api/v1/repos/{owner}/{repo}/pulls/{number}/commits
121 ```
122
123 Required scope: `repo:read`. Returns the commit set ahead of base
124 in order, populated by the synchronize worker after open.
125
126 ## List files changed by a pull request
127
128 ```
129 GET /api/v1/repos/{owner}/{repo}/pulls/{number}/files
130 ```
131
132 Required scope: `repo:read`. Each entry carries `path`, `status`
133 (`added`/`modified`/`removed`/`renamed`), `additions`,
134 `deletions`, and `changes`. `old_path` is set on renames.
135
136 ## Merge a pull request
137
138 ```
139 PUT /api/v1/repos/{owner}/{repo}/pulls/{number}/merge
140 ```
141
142 Required scope: `repo:write`. Policy: `ActionPullMerge`.
143
144 ```json
145 {
146 "commit_title": "Optional override",
147 "commit_message": "Optional body",
148 "merge_method": "merge",
149 "sha": "<head_oid>"
150 }
151 ```
152
153 | Field | Type | Notes |
154 |------------------|--------|----------------------------------------------------|
155 | `commit_title` | string | Subject override; falls back to `"<title> (#<number>)"`. |
156 | `commit_message` | string | Body for the merge commit. Ignored on rebase. |
157 | `merge_method` | string | `"merge"`, `"squash"`, `"rebase"` — must be enabled on the repo. Defaults to the repo's default merge method. |
158 | `sha` | string | Optional `head_oid` guard; `409` on mismatch. |
159
160 Returns `200` with the freshly-loaded PR (state now `closed`,
161 `merged` true). `409` when the PR is already merged/closed or
162 when `mergeable_state` isn't `clean`. `422` when the requested
163 merge method is disabled on the repo or when no commits are
164 ahead of base. `503` if another merge is in flight.
165
166 ## Reviews
167
168 PR reviews bundle a verdict (`approve`, `request_changes`, or
169 `comment`) with optional body and any draft inline comments the
170 caller had pending on this PR.
171
172 ### List reviews
173
174 ```
175 GET /api/v1/repos/{owner}/{repo}/pulls/{number}/reviews
176 ```
177
178 Required scope: `repo:read`. Returns submitted reviews in
179 creation order.
180
181 ### Submit a review
182
183 ```
184 POST /api/v1/repos/{owner}/{repo}/pulls/{number}/reviews
185 ```
186
187 Required scope: `repo:write`. Policy: `ActionPullReview`
188 reviewers must be repo collaborators with at least write access.
189
190 ```json
191 { "event": "APPROVE", "body": "looks good to me" }
192 ```
193
194 `event` is one of `APPROVE`, `REQUEST_CHANGES`, `COMMENT`
195 (lowercase accepted too). Submitting `APPROVE` as the PR author
196 returns `403`. Submitting attaches every pending inline comment
197 the caller authored on this PR.
198
199 ## Inline review comments
200
201 ### List
202
203 ```
204 GET /api/v1/repos/{owner}/{repo}/pulls/{number}/comments
205 ```
206
207 Required scope: `repo:read`. Returns one entry per inline
208 comment with `file_path`, `side`, `original_commit_sha`,
209 `original_line`, `original_position`, optional `current_position`
210 (absent → outdated), `pending`, `resolved`, and threading via
211 `in_reply_to_id`.
212
213 ### Add
214
215 ```
216 POST /api/v1/repos/{owner}/{repo}/pulls/{number}/comments
217 ```
218
219 Required scope: `repo:write`. Policy: `ActionPullReview`.
220
221 ```json
222 {
223 "body": "nit: unused import",
224 "file_path": "foo.txt",
225 "side": "right",
226 "original_commit_sha": "abc123",
227 "original_line": 12,
228 "original_position": 8,
229 "current_position": 8,
230 "pending": true
231 }
232 ```
233
234 `pending=true` files a draft that's attached to the next review
235 the caller submits. `in_reply_to_id` threads under an existing
236 comment and inherits its diff anchor.
237
238 ## Requested reviewers
239
240 ### List active
241
242 ```
243 GET /api/v1/repos/{owner}/{repo}/pulls/{number}/requested_reviewers
244 ```
245
246 Required scope: `repo:read`. Returns active and historical review
247 requests with `dismissed_at` / `satisfied_by_review_id` set when
248 applicable.
249
250 ### Request a reviewer
251
252 ```
253 POST /api/v1/repos/{owner}/{repo}/pulls/{number}/requested_reviewers
254 ```
255
256 Required scope: `repo:write`. Policy: `ActionPullReview`. Body:
257
258 ```json
259 { "user_id": 42 }
260 ```
261
262 or equivalently `{ "username": "bob" }`. `409` when the user is
263 already an active pending reviewer; `422` on unknown user.
264
265 ### Dismiss a request
266
267 ```
268 DELETE /api/v1/repos/{owner}/{repo}/pulls/{number}/requested_reviewers
269 ```
270
271 Required scope: `repo:write`. Same body. Returns `204`; `404`
272 when there is no active request for that user.
273
274 ## Not yet shipped
275
276 - `PUT /pulls/{n}/update-branch`
277 - `PUT /pulls/{n}/auto-merge`