markdown · 4288 bytes Raw Blame History

Issues

Issues live per repo. They share the issues table with pull requests, but the REST surface here returns issues only (PRs land in their own section). Markdown bodies are stored raw; the cached HTML render comes from the same internal/markdown pipeline the web UI uses.

Issue shape

{
  "id": 17,
  "number": 1,
  "title": "first bug",
  "body": "kaboom",
  "state": "open",
  "state_reason": "",
  "locked": false,
  "lock_reason": "",
  "author_id": 42,
  "labels": ["bug"],
  "created_at": "2026-05-12T05:00:00Z",
  "updated_at": "2026-05-12T05:00:00Z"
}

state is "open" or "closed". state_reason is one of "completed", "not_planned", "duplicate", "reopened", or empty when no reason has been recorded. closed_at is present only on closed issues.

List issues

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

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

Optional ?state=open|closed|all filter; state=all (or omitted) returns both.

Pull requests are not included on this endpoint — fetch them via the pulls surface.

Get a single issue

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

Required scope: repo:read. 404 when the issue doesn't exist, when the caller can't see the repo, or when {number} belongs to a pull request (use the pulls surface).

Create an issue

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

Required scope: repo:write. Policy: ActionIssueCreate.

{ "title": "first bug", "body": "kaboom" }
Field Type Notes
title string Required, 1–256 chars.
body string Optional markdown body, ≤65535 chars.

Returns 201 with the issue envelope.

Errors

Status When
401 PAT missing/invalid.
403 PAT lacks repo:write scope or policy denial.
422 Empty title, title too long, body too long.

Update an issue

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

Required scope: repo:write. Only the fields you send are modified; everything else stays.

{
  "title": "first bug — root cause found",
  "body": "see comment #3",
  "state": "closed",
  "state_reason": "completed"
}

Permission rules:

  • Title / body — the issue author OR a repo collaborator with write access. Other callers 403.
  • State / state_reason — any caller with ActionIssueClose on the repo. state_reason must be one of completed, not_planned, duplicate, reopened (or empty).

Returns the freshly-loaded issue.

Lock and unlock

PUT    /api/v1/repos/{owner}/{repo}/issues/{number}/lock
DELETE /api/v1/repos/{owner}/{repo}/issues/{number}/lock

Required scope: repo:write. PUT body is optional:

{ "lock_reason": "off-topic" }

Returns 204. Locking refuses non-collaborator comments; the issue itself stays visible.

Comments

List

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

Required scope: repo:read. Returns comments in chronological order.

Add

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

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

{ "body": "lgtm" }

Subject to the per-author comment rate limit (20/hour); 429 when exceeded.

Edit own comment

PATCH /api/v1/repos/{owner}/{repo}/issues/comments/{cid}

Required scope: repo:write. The comment author can edit their own; other callers 403.

Delete a comment

DELETE /api/v1/repos/{owner}/{repo}/issues/comments/{cid}

Required scope: repo:write. The comment author can delete their own; repo collaborators with write access can delete any comment on the repo (moderation affordance, matches the gh shape).

Returns 204.

Not yet shipped

POST /api/v1/repos/{o}/{r}/issues/{n}/transfer, pinning, applying labels / assignees / milestones over the issue PATCH — all queued for a follow-up batch.

View source
1 # Issues
2
3 Issues live per repo. They share the `issues` table with pull
4 requests, but the REST surface here returns issues only (PRs land
5 in their own section). Markdown bodies are stored raw; the cached
6 HTML render comes from the same `internal/markdown` pipeline the
7 web UI uses.
8
9 ## Issue shape
10
11 ```json
12 {
13 "id": 17,
14 "number": 1,
15 "title": "first bug",
16 "body": "kaboom",
17 "state": "open",
18 "state_reason": "",
19 "locked": false,
20 "lock_reason": "",
21 "author_id": 42,
22 "labels": ["bug"],
23 "created_at": "2026-05-12T05:00:00Z",
24 "updated_at": "2026-05-12T05:00:00Z"
25 }
26 ```
27
28 `state` is `"open"` or `"closed"`. `state_reason` is one of
29 `"completed"`, `"not_planned"`, `"duplicate"`, `"reopened"`, or
30 empty when no reason has been recorded. `closed_at` is present
31 only on closed issues.
32
33 ## List issues
34
35 ```
36 GET /api/v1/repos/{owner}/{repo}/issues
37 ```
38
39 Required scope: `repo:read`. Paginated; `?per_page=` (≤100) and
40 `?page=` apply, with the standard `Link:` header.
41
42 Optional `?state=open|closed|all` filter; `state=all` (or omitted)
43 returns both.
44
45 Pull requests are not included on this endpoint — fetch them via
46 the pulls surface.
47
48 ## Get a single issue
49
50 ```
51 GET /api/v1/repos/{owner}/{repo}/issues/{number}
52 ```
53
54 Required scope: `repo:read`. `404` when the issue doesn't exist,
55 when the caller can't see the repo, or when `{number}` belongs to
56 a pull request (use the pulls surface).
57
58 ## Create an issue
59
60 ```
61 POST /api/v1/repos/{owner}/{repo}/issues
62 ```
63
64 Required scope: `repo:write`. Policy: `ActionIssueCreate`.
65
66 ```json
67 { "title": "first bug", "body": "kaboom" }
68 ```
69
70 | Field | Type | Notes |
71 |---------|--------|-----------------------------------------------|
72 | `title` | string | Required, 1–256 chars. |
73 | `body` | string | Optional markdown body, ≤65535 chars. |
74
75 Returns `201` with the issue envelope.
76
77 ### Errors
78
79 | Status | When |
80 |-------:|---------------------------------------------------|
81 | 401 | PAT missing/invalid. |
82 | 403 | PAT lacks `repo:write` scope or policy denial. |
83 | 422 | Empty title, title too long, body too long. |
84
85 ## Update an issue
86
87 ```
88 PATCH /api/v1/repos/{owner}/{repo}/issues/{number}
89 ```
90
91 Required scope: `repo:write`. Only the fields you send are
92 modified; everything else stays.
93
94 ```json
95 {
96 "title": "first bug — root cause found",
97 "body": "see comment #3",
98 "state": "closed",
99 "state_reason": "completed"
100 }
101 ```
102
103 Permission rules:
104
105 - **Title / body** — the issue author OR a repo collaborator with
106 write access. Other callers `403`.
107 - **State / state_reason** — any caller with `ActionIssueClose`
108 on the repo. `state_reason` must be one of `completed`,
109 `not_planned`, `duplicate`, `reopened` (or empty).
110
111 Returns the freshly-loaded issue.
112
113 ## Lock and unlock
114
115 ```
116 PUT /api/v1/repos/{owner}/{repo}/issues/{number}/lock
117 DELETE /api/v1/repos/{owner}/{repo}/issues/{number}/lock
118 ```
119
120 Required scope: `repo:write`. PUT body is optional:
121
122 ```json
123 { "lock_reason": "off-topic" }
124 ```
125
126 Returns `204`. Locking refuses non-collaborator comments; the
127 issue itself stays visible.
128
129 ## Comments
130
131 ### List
132
133 ```
134 GET /api/v1/repos/{owner}/{repo}/issues/{number}/comments
135 ```
136
137 Required scope: `repo:read`. Returns comments in chronological
138 order.
139
140 ### Add
141
142 ```
143 POST /api/v1/repos/{owner}/{repo}/issues/{number}/comments
144 ```
145
146 Required scope: `repo:write`. Policy: `ActionIssueComment`. Body:
147
148 ```json
149 { "body": "lgtm" }
150 ```
151
152 Subject to the per-author comment rate limit (20/hour); `429`
153 when exceeded.
154
155 ### Edit own comment
156
157 ```
158 PATCH /api/v1/repos/{owner}/{repo}/issues/comments/{cid}
159 ```
160
161 Required scope: `repo:write`. The comment author can edit their
162 own; other callers `403`.
163
164 ### Delete a comment
165
166 ```
167 DELETE /api/v1/repos/{owner}/{repo}/issues/comments/{cid}
168 ```
169
170 Required scope: `repo:write`. The comment author can delete their
171 own; repo collaborators with write access can delete any comment
172 on the repo (moderation affordance, matches the gh shape).
173
174 Returns `204`.
175
176 ## Not yet shipped
177
178 `POST /api/v1/repos/{o}/{r}/issues/{n}/transfer`, pinning,
179 applying labels / assignees / milestones over the issue PATCH —
180 all queued for a follow-up batch.