Issues API
create, read, update, and close issues with labels, milestones, assignees, and reactions
Authentication
All write operations require a bearer token. Pass it as:
Authorization: Bearer <token>
or the legacy form Authorization: token <token>. Set Accept: application/vnd.github+json on every request.
Issue object
A representative issue response:
{
"id": 1,
"node_id": "I_kgDOBc3xAA",
"number": 42,
"title": "panic when repo has no commits",
"body": "Steps to reproduce:\n1. Create a bare repo\n2. Clone it\n3. Visit /owner/repo\n\nStack trace attached.",
"state": "open",
"state_reason": null,
"locked": false,
"user": {
"login": "alice",
"id": 5,
"node_id": "U_kgDOAA5",
"avatar_url": "https://git.example.com/avatars/alice",
"type": "User"
},
"assignees": [
{
"login": "bob",
"id": 7,
"node_id": "U_kgDOAA7",
"type": "User"
}
],
"labels": [
{
"id": 3,
"node_id": "LA_kgDOAA3",
"name": "bug",
"color": "d73a4a",
"description": "Something isn't working",
"default": true
}
],
"milestone": {
"id": 2,
"node_id": "MI_kgDOAA2",
"number": 1,
"title": "v1.0",
"state": "open",
"due_on": "2026-09-01T00:00:00Z"
},
"comments": 3,
"created_at": "2026-05-10T09:14:22Z",
"updated_at": "2026-06-01T14:05:33Z",
"closed_at": null,
"url": "https://git.example.com/api/v3/repos/alice/myrepo/issues/42",
"html_url": "https://git.example.com/alice/myrepo/issues/42",
"repository_url": "https://git.example.com/api/v3/repos/alice/myrepo"
}
Create an issue
POST /repos/{owner}/{repo}/issues
Request body fields:
| Field | Type | Required | Description |
|---|---|---|---|
title |
string | yes | Issue title |
body |
string | no | Markdown body |
labels |
array of strings | no | Label names to attach |
assignees |
array of strings | no | Logins to assign |
milestone |
integer | no | Milestone number |
curl -X POST https://git.example.com/repos/alice/myrepo/issues \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "Content-Type: application/json" \
-d '{
"title": "panic when repo has no commits",
"body": "Steps to reproduce:\n1. Create a bare repo\n2. Clone it",
"labels": ["bug"],
"assignees": ["bob"],
"milestone": 1
}'
Returns 201 Created with the full issue object.
List issues
GET /repos/{owner}/{repo}/issues
Query parameters:
| Parameter | Values | Default |
|---|---|---|
state |
open, closed, all |
open |
sort |
created, updated, comments |
created |
direction |
asc, desc |
desc |
labels |
comma-separated label names | |
assignee |
login, none, * |
|
milestone |
milestone number, none, * |
|
since |
ISO 8601 timestamp | |
per_page |
1-100 | 30 |
page |
integer | 1 |
# open bugs assigned to alice, newest first
curl "https://git.example.com/repos/alice/myrepo/issues?state=open&labels=bug&assignee=alice&sort=created&direction=desc" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json"
# issues updated after a specific timestamp
curl "https://git.example.com/repos/alice/myrepo/issues?state=all&since=2026-01-01T00:00:00Z&per_page=100" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json"
Returns 200 OK with an array of issue objects. Pagination links are in the Link response header.
Get a single issue
GET /repos/{owner}/{repo}/issues/{number}
curl https://git.example.com/repos/alice/myrepo/issues/42 \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json"
Update an issue
PATCH /repos/{owner}/{repo}/issues/{number}
All fields are optional. Only provided fields are changed.
# close an issue as completed
curl -X PATCH https://git.example.com/repos/alice/myrepo/issues/42 \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "Content-Type: application/json" \
-d '{"state": "closed", "state_reason": "completed"}'
# close as not planned
curl -X PATCH https://git.example.com/repos/alice/myrepo/issues/42 \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "Content-Type: application/json" \
-d '{"state": "closed", "state_reason": "not_planned"}'
# reopen
curl -X PATCH https://git.example.com/repos/alice/myrepo/issues/42 \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "Content-Type: application/json" \
-d '{"state": "open", "state_reason": "reopened"}'
# retitle, reassign, relabel in one call
curl -X PATCH https://git.example.com/repos/alice/myrepo/issues/42 \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "Content-Type: application/json" \
-d '{
"title": "panic when repo has no commits (reproducible)",
"assignees": ["carol"],
"labels": ["bug", "good first issue"]
}'
The state_reason field accepts completed, not_planned, or reopened. It is null when the issue is open with no prior close reason.
Comments
List comments on an issue
GET /repos/{owner}/{repo}/issues/{number}/comments
curl "https://git.example.com/repos/alice/myrepo/issues/42/comments?per_page=30&page=1" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json"
Create a comment
POST /repos/{owner}/{repo}/issues/{number}/comments
curl -X POST https://git.example.com/repos/alice/myrepo/issues/42/comments \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "Content-Type: application/json" \
-d '{"body": "Confirmed on main. The nil pointer is in `pkg/web/tree.go:84`."}'
Returns 201 Created.
Get a comment
GET /repos/{owner}/{repo}/issues/comments/{id}
curl https://git.example.com/repos/alice/myrepo/issues/comments/101 \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json"
Update a comment
PATCH /repos/{owner}/{repo}/issues/comments/{id}
curl -X PATCH https://git.example.com/repos/alice/myrepo/issues/comments/101 \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "Content-Type: application/json" \
-d '{"body": "Confirmed on main and 0.9.x."}'
Delete a comment
DELETE /repos/{owner}/{repo}/issues/comments/{id}
curl -X DELETE https://git.example.com/repos/alice/myrepo/issues/comments/101 \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json"
Returns 204 No Content.
Labels
List labels in a repo
GET /repos/{owner}/{repo}/labels
curl https://git.example.com/repos/alice/myrepo/labels \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json"
Create a label
POST /repos/{owner}/{repo}/labels
color is a 6-character hex string without the # prefix.
curl -X POST https://git.example.com/repos/alice/myrepo/labels \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "Content-Type: application/json" \
-d '{
"name": "performance",
"color": "0075ca",
"description": "Relates to runtime or memory performance"
}'
Returns 201 Created.
List labels on an issue
GET /repos/{owner}/{repo}/issues/{number}/labels
curl https://git.example.com/repos/alice/myrepo/issues/42/labels \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json"
Add labels to an issue
POST /repos/{owner}/{repo}/issues/{number}/labels
curl -X POST https://git.example.com/repos/alice/myrepo/issues/42/labels \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "Content-Type: application/json" \
-d '{"labels": ["performance", "help wanted"]}'
Remove a label from an issue
DELETE /repos/{owner}/{repo}/issues/{number}/labels/{name}
curl -X DELETE https://git.example.com/repos/alice/myrepo/issues/42/labels/performance \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json"
Returns 200 OK with the remaining labels array.
Milestones
List milestones
GET /repos/{owner}/{repo}/milestones
curl "https://git.example.com/repos/alice/myrepo/milestones?state=open&sort=due_on&direction=asc" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json"
Create a milestone
POST /repos/{owner}/{repo}/milestones
curl -X POST https://git.example.com/repos/alice/myrepo/milestones \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "Content-Type: application/json" \
-d '{
"title": "v1.0",
"description": "First stable release",
"due_on": "2026-09-01T00:00:00Z",
"state": "open"
}'
Returns 201 Created with the milestone object, including open_issues and closed_issues counts.
Assignees
Assignees are set via the assignees field when creating or updating an issue. To list users eligible for assignment in a repo:
GET /repos/{owner}/{repo}/assignees
curl https://git.example.com/repos/alice/myrepo/assignees \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json"
Reactions
List reactions on an issue
GET /repos/{owner}/{repo}/issues/{number}/reactions
curl https://git.example.com/repos/alice/myrepo/issues/42/reactions \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json"
Add a reaction
POST /repos/{owner}/{repo}/issues/{number}/reactions
The content field accepts one of: +1, -1, laugh, hooray, confused, heart, rocket, eyes.
curl -X POST https://git.example.com/repos/alice/myrepo/issues/42/reactions \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json" \
-H "Content-Type: application/json" \
-d '{"content": "+1"}'
Returns 201 Created if the reaction is new, or 200 OK if the authenticated user already reacted with the same content.
{
"id": 55,
"node_id": "RE_kgDOAA3z",
"content": "+1",
"user": {
"login": "carol",
"id": 9,
"type": "User"
},
"created_at": "2026-06-10T08:22:10Z"
}
Search issues
Use the search API to query across repos:
GET /search/issues?q={query}
# open bugs in a specific repo
curl "https://git.example.com/search/issues?q=panic+label:bug+repo:alice/myrepo+state:open" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/vnd.github+json"
Returns {"total_count": N, "incomplete_results": false, "items": [...]}.