17 KiB
GitHub API Reference
This reference provides comprehensive documentation for GitHub REST and GraphQL APIs, focusing on common operations accessible via gh api.
Table of Contents
- Authentication
- Pull Requests API
- Issues API
- Repositories API
- Actions/Workflows API
- Search API
- GraphQL API
- Rate Limiting
- Webhooks
Authentication
All API calls via gh api automatically use the authenticated token from gh auth login.
# Check authentication status
gh auth status
# View current token (use cautiously)
gh auth status --show-token
API Headers:
Accept: application/vnd.github+json(automatically set)X-GitHub-Api-Version: 2022-11-28(recommended)
Pull Requests API
List Pull Requests
Endpoint: GET /repos/{owner}/{repo}/pulls
# List all open PRs
gh api repos/{owner}/{repo}/pulls
# List PRs with filters
gh api repos/{owner}/{repo}/pulls -f state=closed -f base=main
# List PRs sorted by updated
gh api repos/{owner}/{repo}/pulls -f sort=updated -f direction=desc
Query Parameters:
state:open,closed,all(default:open)head: Filter by branch name (format:user:ref-name)base: Filter by base branchsort:created,updated,popularity,long-runningdirection:asc,descper_page: Results per page (max: 100)page: Page number
Get Pull Request
Endpoint: GET /repos/{owner}/{repo}/pulls/{pull_number}
# Get PR details
gh api repos/{owner}/{repo}/pulls/123
# Get PR with specific fields
gh api repos/{owner}/{repo}/pulls/123 --jq '.title, .state, .mergeable'
Response includes:
- Basic PR info (title, body, state)
- Author and assignees
- Labels, milestone
- Merge status and conflicts
- Review status
- Head and base branch info
Create Pull Request
Endpoint: POST /repos/{owner}/{repo}/pulls
# Create PR via API
gh api repos/{owner}/{repo}/pulls \
-f title="NOJIRA: New feature" \
-f body="Description of changes" \
-f head="feature-branch" \
-f base="main"
# Create draft PR
gh api repos/{owner}/{repo}/pulls \
-f title="WIP: Feature" \
-f body="Work in progress" \
-f head="feature-branch" \
-f base="main" \
-F draft=true
Required fields:
title: PR titlehead: Branch containing changesbase: Branch to merge into
Optional fields:
body: PR descriptiondraft: Boolean for draft PRmaintainer_can_modify: Allow maintainer edits
Update Pull Request
Endpoint: PATCH /repos/{owner}/{repo}/pulls/{pull_number}
# Update PR title and body
gh api repos/{owner}/{repo}/pulls/123 \
-X PATCH \
-f title="Updated title" \
-f body="Updated description"
# Convert to draft
gh api repos/{owner}/{repo}/pulls/123 \
-X PATCH \
-F draft=true
# Change base branch
gh api repos/{owner}/{repo}/pulls/123 \
-X PATCH \
-f base="develop"
Merge Pull Request
Endpoint: PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge
# Merge with commit message
gh api repos/{owner}/{repo}/pulls/123/merge \
-X PUT \
-f commit_title="Merge PR #123" \
-f commit_message="Additional merge message" \
-f merge_method="squash"
# Merge methods: merge, squash, rebase
List PR Comments
Endpoint: GET /repos/{owner}/{repo}/pulls/{pull_number}/comments
# Get all review comments
gh api repos/{owner}/{repo}/pulls/123/comments
# Get issue comments (conversation tab)
gh api repos/{owner}/{repo}/issues/123/comments
Create PR Review
Endpoint: POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews
# Approve PR
gh api repos/{owner}/{repo}/pulls/123/reviews \
-f event="APPROVE" \
-f body="Looks good!"
# Request changes
gh api repos/{owner}/{repo}/pulls/123/reviews \
-f event="REQUEST_CHANGES" \
-f body="Please address these issues"
# Comment without approval/rejection
gh api repos/{owner}/{repo}/pulls/123/reviews \
-f event="COMMENT" \
-f body="Some feedback"
Review events:
APPROVE: Approve the PRREQUEST_CHANGES: Request changesCOMMENT: General comment
List PR Reviews
Endpoint: GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews
# Get all reviews
gh api repos/{owner}/{repo}/pulls/123/reviews
# Parse review states
gh api repos/{owner}/{repo}/pulls/123/reviews --jq '[.[] | {user: .user.login, state: .state}]'
Request Reviewers
Endpoint: POST /repos/{owner}/{repo}/pulls/{pull_number}/requested_reviewers
# Request user reviewers
gh api repos/{owner}/{repo}/pulls/123/requested_reviewers \
-f reviewers[]="user1" \
-f reviewers[]="user2"
# Request team reviewers
gh api repos/{owner}/{repo}/pulls/123/requested_reviewers \
-f team_reviewers[]="team-slug"
Issues API
List Issues
Endpoint: GET /repos/{owner}/{repo}/issues
# List all issues
gh api repos/{owner}/{repo}/issues
# Filter by state and labels
gh api repos/{owner}/{repo}/issues -f state=open -f labels="bug,priority-high"
# Filter by assignee
gh api repos/{owner}/{repo}/issues -f assignee="username"
# Filter by milestone
gh api repos/{owner}/{repo}/issues -f milestone="v1.0"
Query Parameters:
state:open,closed,alllabels: Comma-separated label namesassignee: Username ornoneor*creator: Usernamementioned: Usernamemilestone: Milestone number ornoneor*sort:created,updated,commentsdirection:asc,desc
Create Issue
Endpoint: POST /repos/{owner}/{repo}/issues
# Create basic issue
gh api repos/{owner}/{repo}/issues \
-f title="Bug: Something broke" \
-f body="Detailed description"
# Create issue with labels and assignees
gh api repos/{owner}/{repo}/issues \
-f title="Enhancement request" \
-f body="Description" \
-f labels[]="enhancement" \
-f labels[]="good-first-issue" \
-f assignees[]="username1"
Update Issue
Endpoint: PATCH /repos/{owner}/{repo}/issues/{issue_number}
# Close issue
gh api repos/{owner}/{repo}/issues/456 \
-X PATCH \
-f state="closed"
# Update labels
gh api repos/{owner}/{repo}/issues/456 \
-X PATCH \
-f labels[]="bug" \
-f labels[]="fixed"
# Assign issue
gh api repos/{owner}/{repo}/issues/456 \
-X PATCH \
-f assignees[]="username"
Add Comment to Issue
Endpoint: POST /repos/{owner}/{repo}/issues/{issue_number}/comments
# Add comment
gh api repos/{owner}/{repo}/issues/456/comments \
-f body="This is a comment"
Repositories API
Get Repository
Endpoint: GET /repos/{owner}/{repo}
# Get repository details
gh api repos/{owner}/{repo}
# Get specific fields
gh api repos/{owner}/{repo} --jq '{name: .name, stars: .stargazers_count, forks: .forks_count}'
List Branches
Endpoint: GET /repos/{owner}/{repo}/branches
# List all branches
gh api repos/{owner}/{repo}/branches
# Get branch names only
gh api repos/{owner}/{repo}/branches --jq '.[].name'
Get Branch
Endpoint: GET /repos/{owner}/{repo}/branches/{branch}
# Get branch details
gh api repos/{owner}/{repo}/branches/main
# Check if branch is protected
gh api repos/{owner}/{repo}/branches/main --jq '.protected'
Get Branch Protection
Endpoint: GET /repos/{owner}/{repo}/branches/{branch}/protection
# Get protection rules
gh api repos/{owner}/{repo}/branches/main/protection
List Commits
Endpoint: GET /repos/{owner}/{repo}/commits
# List recent commits
gh api repos/{owner}/{repo}/commits
# Filter by branch
gh api repos/{owner}/{repo}/commits -f sha="feature-branch"
# Filter by author
gh api repos/{owner}/{repo}/commits -f author="username"
# Filter by date range
gh api repos/{owner}/{repo}/commits -f since="2024-01-01T00:00:00Z"
Get Commit
Endpoint: GET /repos/{owner}/{repo}/commits/{sha}
# Get commit details
gh api repos/{owner}/{repo}/commits/abc123
# Get files changed in commit
gh api repos/{owner}/{repo}/commits/abc123 --jq '.files[].filename'
Get Commit Status
Endpoint: GET /repos/{owner}/{repo}/commits/{sha}/status
# Get combined status for commit
gh api repos/{owner}/{repo}/commits/abc123/status
# Check if all checks passed
gh api repos/{owner}/{repo}/commits/abc123/status --jq '.state'
List Collaborators
Endpoint: GET /repos/{owner}/{repo}/collaborators
# List all collaborators
gh api repos/{owner}/{repo}/collaborators
# Get collaborator permissions
gh api repos/{owner}/{repo}/collaborators --jq '[.[] | {login: .login, permissions: .permissions}]'
Create Release
Endpoint: POST /repos/{owner}/{repo}/releases
# Create release
gh api repos/{owner}/{repo}/releases \
-f tag_name="v1.0.0" \
-f name="Release v1.0.0" \
-f body="Release notes here" \
-F draft=false \
-F prerelease=false
# Create draft release
gh api repos/{owner}/{repo}/releases \
-f tag_name="v1.1.0" \
-f name="Release v1.1.0" \
-f body="Release notes" \
-F draft=true
List Releases
Endpoint: GET /repos/{owner}/{repo}/releases
# List all releases
gh api repos/{owner}/{repo}/releases
# Get latest release
gh api repos/{owner}/{repo}/releases/latest
Actions/Workflows API
List Workflows
Endpoint: GET /repos/{owner}/{repo}/actions/workflows
# List all workflows
gh api repos/{owner}/{repo}/actions/workflows
# Get workflow names
gh api repos/{owner}/{repo}/actions/workflows --jq '.workflows[].name'
Get Workflow
Endpoint: GET /repos/{owner}/{repo}/actions/workflows/{workflow_id}
# Get workflow by ID
gh api repos/{owner}/{repo}/actions/workflows/12345
# Get workflow by filename
gh api repos/{owner}/{repo}/actions/workflows/ci.yml
List Workflow Runs
Endpoint: GET /repos/{owner}/{repo}/actions/runs
# List all runs
gh api repos/{owner}/{repo}/actions/runs
# Filter by workflow
gh api repos/{owner}/{repo}/actions/runs -f workflow_id=12345
# Filter by branch
gh api repos/{owner}/{repo}/actions/runs -f branch="main"
# Filter by status
gh api repos/{owner}/{repo}/actions/runs -f status="completed"
# Filter by conclusion
gh api repos/{owner}/{repo}/actions/runs -f conclusion="success"
Status values: queued, in_progress, completed
Conclusion values: success, failure, cancelled, skipped, timed_out, action_required
Get Workflow Run
Endpoint: GET /repos/{owner}/{repo}/actions/runs/{run_id}
# Get run details
gh api repos/{owner}/{repo}/actions/runs/123456
# Check run status
gh api repos/{owner}/{repo}/actions/runs/123456 --jq '.status, .conclusion'
Trigger Workflow
Endpoint: POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches
# Trigger workflow on branch
gh api repos/{owner}/{repo}/actions/workflows/ci.yml/dispatches \
-f ref="main"
# Trigger with inputs
gh api repos/{owner}/{repo}/actions/workflows/deploy.yml/dispatches \
-f ref="main" \
-f inputs[environment]="production" \
-f inputs[version]="v1.0.0"
Cancel Workflow Run
Endpoint: POST /repos/{owner}/{repo}/actions/runs/{run_id}/cancel
# Cancel run
gh api repos/{owner}/{repo}/actions/runs/123456/cancel -X POST
Rerun Workflow
Endpoint: POST /repos/{owner}/{repo}/actions/runs/{run_id}/rerun
# Rerun all jobs
gh api repos/{owner}/{repo}/actions/runs/123456/rerun -X POST
# Rerun failed jobs only
gh api repos/{owner}/{repo}/actions/runs/123456/rerun-failed-jobs -X POST
Download Workflow Logs
Endpoint: GET /repos/{owner}/{repo}/actions/runs/{run_id}/logs
# Download logs (returns zip archive)
gh api repos/{owner}/{repo}/actions/runs/123456/logs > logs.zip
Search API
Search Repositories
Endpoint: GET /search/repositories
# Search repositories
gh api search/repositories -f q="topic:spring-boot language:java"
# Search with filters
gh api search/repositories -f q="stars:>1000 language:python"
Search Code
Endpoint: GET /search/code
# Search code
gh api search/code -f q="addClass repo:owner/repo"
# Search in specific path
gh api search/code -f q="function path:src/ repo:owner/repo"
Search Issues and PRs
Endpoint: GET /search/issues
# Search issues
gh api search/issues -f q="is:issue is:open label:bug repo:owner/repo"
# Search PRs
gh api search/issues -f q="is:pr is:merged author:username"
GraphQL API
Basic GraphQL Query
# Execute GraphQL query
gh api graphql -f query='
query {
viewer {
login
name
}
}
'
Query Repository Information
gh api graphql -f query='
query($owner: String!, $name: String!) {
repository(owner: $owner, name: $name) {
name
description
stargazerCount
forkCount
issues(states: OPEN) {
totalCount
}
pullRequests(states: OPEN) {
totalCount
}
}
}
' -f owner="owner" -f name="repo"
Query PR with Reviews
gh api graphql -f query='
query($owner: String!, $name: String!, $number: Int!) {
repository(owner: $owner, name: $name) {
pullRequest(number: $number) {
title
state
author {
login
}
reviews(first: 10) {
nodes {
state
author {
login
}
submittedAt
}
}
commits(last: 1) {
nodes {
commit {
statusCheckRollup {
state
}
}
}
}
}
}
}
' -f owner="owner" -f name="repo" -F number=123
Query Multiple PRs with Pagination
gh api graphql -f query='
query($owner: String!, $name: String!, $cursor: String) {
repository(owner: $owner, name: $name) {
pullRequests(first: 10, states: OPEN, after: $cursor) {
pageInfo {
hasNextPage
endCursor
}
nodes {
number
title
author {
login
}
createdAt
}
}
}
}
' -f owner="owner" -f name="repo"
Rate Limiting
Check Rate Limit
Endpoint: GET /rate_limit
# Check current rate limit
gh api rate_limit
# Check core API limit
gh api rate_limit --jq '.resources.core'
# Check GraphQL limit
gh api rate_limit --jq '.resources.graphql'
Rate limits:
- Authenticated: 5,000 requests/hour
- GraphQL: 5,000 points/hour
- Search: 30 requests/minute
Rate Limit Headers
Every API response includes rate limit headers:
X-RateLimit-Limit: Total requests allowedX-RateLimit-Remaining: Requests remainingX-RateLimit-Reset: Unix timestamp when limit resets
Webhooks
List Webhooks
Endpoint: GET /repos/{owner}/{repo}/hooks
# List repository webhooks
gh api repos/{owner}/{repo}/hooks
Create Webhook
Endpoint: POST /repos/{owner}/{repo}/hooks
# Create webhook
gh api repos/{owner}/{repo}/hooks \
-f name="web" \
-f config[url]="https://example.com/webhook" \
-f config[content_type]="json" \
-f events[]="push" \
-f events[]="pull_request"
Test Webhook
Endpoint: POST /repos/{owner}/{repo}/hooks/{hook_id}/tests
# Test webhook
gh api repos/{owner}/{repo}/hooks/12345/tests -X POST
Pagination
For endpoints returning lists, use pagination:
# First page (default)
gh api repos/{owner}/{repo}/issues
# Specific page
gh api repos/{owner}/{repo}/issues -f page=2 -f per_page=50
# Iterate through all pages
for page in {1..10}; do
gh api repos/{owner}/{repo}/issues -f page=$page -f per_page=100
done
Link header: Response includes Link header with next, prev, first, last URLs.
Error Handling
Common HTTP status codes:
200 OK: Success201 Created: Resource created204 No Content: Success with no response body400 Bad Request: Invalid request401 Unauthorized: Authentication required403 Forbidden: Insufficient permissions or rate limited404 Not Found: Resource doesn't exist422 Unprocessable Entity: Validation failed
Error response format:
{
"message": "Validation Failed",
"errors": [
{
"resource": "PullRequest",
"code": "custom",
"message": "Error details"
}
]
}
Best Practices
- Use conditional requests: Include
If-None-Matchheader with ETag to save rate limit quota - Paginate efficiently: Use
per_page=100(maximum) to minimize requests - Use GraphQL for complex queries: Fetch multiple related resources in single request
- Check rate limits proactively: Monitor
X-RateLimit-Remainingheader - Handle errors gracefully: Implement retry logic with exponential backoff for 5xx errors
- Cache responses: Cache GET responses when data doesn't change frequently
- Use webhooks: Subscribe to events instead of polling
Additional Resources
- GitHub REST API documentation: https://docs.github.com/en/rest
- GitHub GraphQL API documentation: https://docs.github.com/en/graphql
- gh CLI manual: https://cli.github.com/manual/