GH-API(1)
π GH-API(1) β the GitHub CLI manual, but make it make sense
okay bestie, this is gh-api, and it's from the GitHub CLI manual, no cap. if you've ever wanted your terminal to just talk to GitHub for you β authenticated, no fuss β this is the one. let's get into it π«Ά
β¨ NAME
gh-api β Make an authenticated GitHub API request
πΈ SYNOPSIS
gh api <endpoint> [flags]
π¦ DESCRIPTION
So here's the vibe: it makes an authenticated HTTP request to the GitHub API and prints the response. that's the whole thing. iconic. π
the endpoint argument
The endpoint argument should either be a path of a GitHub API v3 endpoint, or literally the word graphql if you're trying to access the GitHub API v4. yes, graphql is the secret password. iykyk β¨
placeholders, aka magic curly braces
Placeholder values {owner}, {repo}, and {branch} in the endpoint argument will get replaced with values from the repository of the current directory, or from the repository specified in the GH_REPO environment variable. chef's kiss, truly π
okay but lowkey heads up: in some shells β PowerShell, looking at you π β you may need to enclose any value that contains {...} in quotes, so the shell doesn't go applying special meaning to your curly braces. don't let the shell steal your moment.
previews, babes
The -p/--preview flag enables opting into previews, which are feature-flagged, experimental API endpoints or behaviors. The API expects opt-in via the Accept header with format application/vnd.github.<preview-name>-preview+json, and this command facilitates that via --preview <preview-name>.
So to send a request for the corsair and scarlet-witch previews, you could use -p corsair,scarlet-witch or --preview corsair --preview scarlet-witch. both work, both slay π
method vibes
The default HTTP request method is GET normally, and POST if any parameters were added. Override the method with --method. simple as that π
parameters: -f vs -F
Pass one or more -f/--raw-field values in key=value format to add static string parameters to the request payload. To add non-string or placeholder-determined values, see -F/--field below.
β οΈ note that adding request parameters will automatically switch the request method toPOST. if that's not what you want and you need the parameters as aGETquery string instead, use--method GET. no cap, this trips people up.
The -F/--field flag has magic type conversion based on the format of the value π
- literal values
true,false,null, and integer numbers get converted to appropriate JSON types; - placeholder values
{owner},{repo}, and{branch}get populated with values from the repository of the current directory; - if the value starts with
@, the rest of the value is interpreted as a filename to read the value from. Pass-to read from standard input.
For GraphQL requests, all fields other than query and operationName are interpreted as GraphQL variables. periodt. π§
nesting & arrays
To pass nested parameters in the request payload, use key[subkey]=value syntax when declaring fields. To pass nested values as arrays, declare multiple fields with the syntax key[]=value1, key[]=value2. To pass an empty array, use key[] without a value. the little things matter π
bodies from a file
To pass pre-constructed JSON or payloads in other formats, a request body may be read from file specified by --input. Use - to read from standard input. When passing the request body this way, any parameters specified via field flags are added to the query string of the endpoint URL. sneaky but correct π
pagination, the main character
In --paginate mode, all pages of results will sequentially be requested until there are no more pages of results. For GraphQL requests, this requires that the original query accepts an $endCursor: String variable and that it fetches the pageInfo{ hasNextPage, endCursor } set of fields from a collection. Each page is a separate JSON array or object.
Pass --slurp to wrap all pages of JSON arrays or objects into an outer JSON array. boom, one big beautiful array β¨
π OPTIONS
--allow-escape-sequencesβ Allow printing terminal escape sequences--cache <duration>β Cache the response, e.g."3600s","60m","1h"-F,--field <key=value>β Add a typed parameter inkey=valueformat (use"@"or"@-"to read value from file or stdin)-H,--header <key:value>β Add a HTTP request header inkey:valueformat--hostname <string>β The GitHub hostname for the request (default"github.com")-i,--includeβ Include HTTP response status line and headers in the output--input <file>β The file to use as body for the HTTP request (use"-"to read from standard input)-q,--jq <string>β Query to select values from the response usingjqsyntax-X,--method <string>(default"GET") β The HTTP method for the request--paginateβ Make additional HTTP requests to fetch all pages of results-p,--preview <strings>β Opt into GitHub API previews (names should omit'-preview')-f,--raw-field <key=value>β Add a string parameter inkey=valueformat--silentβ Do not print the response body--slurpβ Use with"--paginate"to return an array of all pages of either JSON arrays or objects-t,--template <string>β Format JSON output using a Go template; see"gh help formatting"--verboseβ Include full HTTP request and response in the output
π EXIT CODES
okay so when things end, here's how they end:
0: Successful execution1: Error2: Command canceled4: Authentication required
NOTE: Specific commands may have additional exit codes. Refer to the command's help for more information. don't come for me if your exit code isn't on this list π
π₯ EXAMPLE
this is the good part. screenshots-worthy. let's go π
List releases in the current repository:
# List releases in the current repository
$ gh api repos/{owner}/{repo}/releases
Post an issue comment:
# Post an issue comment
$ gh api repos/{owner}/{repo}/issues/123/comments -f body='Hi from CLI'
Post nested parameter read from a file:
# Post nested parameter read from a file
$ gh api gists -F 'files[myfile.txt][content]=@myfile.txt'
Add parameters to a GET request:
# Add parameters to a GET request
$ gh api -X GET search/issues -f q='repo:cli/cli is:open remote'
Use a JSON file as request body:
# Use a JSON file as request body
$ gh api repos/{owner}/{repo}/rulesets --input file.json
Set a custom HTTP header:
# Set a custom HTTP header
$ gh api -H 'Accept: application/vnd.github.v3.raw+json' ...
Opt into GitHub API previews:
# Opt into GitHub API previews
$ gh api --preview baptiste,nebula ...
Print only specific fields from the response:
# Print only specific fields from the response
$ gh api repos/{owner}/{repo}/issues --jq '.[].title'
Use a template for the output:
# Use a template for the output
$ gh api repos/{owner}/{repo}/issues --template \
'{{range .}}{{.title}} ({{.labels | pluck "name" | join ", " | color "yellow"}}){{"\n"}}{{end}}'
Update allowed values of the "environment" custom property in a deeply nested array:
# Update allowed values of the "environment" custom property in a deeply nested array
$ gh api -X PATCH /orgs/{org}/properties/schema \
-F 'properties[][property_name]=environment' \
-F 'properties[][default_value]=production' \
-F 'properties[][allowed_values][]=staging' \
-F 'properties[][allowed_values][]=production'
List releases with GraphQL:
# List releases with GraphQL
$ gh api graphql -F owner='{owner}' -F name='{repo}' -f query='
query($name: String!, $owner: String!) {
repository(owner: $owner, name: $name) {
releases(last: 3) {
nodes { tagName }
}
}
}
'
List all repositories for a user:
# List all repositories for a user
$ gh api graphql --paginate -f query='
query($endCursor: String) {
viewer {
repositories(first: 100, after: $endCursor) {
nodes { nameWithOwner }
pageInfo {
hasNextPage
endCursor
}
}
}
}
'
Get the percentage of forks for the current user:
# Get the percentage of forks for the current user
$ gh api graphql --paginate --slurp -f query='
query($endCursor: String) {
viewer {
repositories(first: 100, after: $endCursor) {
nodes { isFork }
pageInfo {
hasNextPage
endCursor
}
}
}
}
' | jq 'def count(e): reduce e as $_ (0;.+1);
[.[].data.viewer.repositories.nodes[]] as $r | count(select($r[].isFork))/count($r[])'
π SEE ALSO
gh(1)β the main character herself π«Ά
that's the whole page bestie, go forth and hit that API responsibly β¨
with love, from the GitHub CLI crew β version v2.102.0, dated Oct 2026. mwah π
π¦ where this page comes from
- opensuse-leap 16.0: gh 2.102.0-bp160.1.1 Β· MIT
- opensuse-leap 16.0: gh 2.102.0-bp160.1.1 Β· MIT
- opensuse-leap 16.0: gh 2.102.0-bp160.1.1 Β· MIT
- opensuse-leap 16.0: gh 2.102.0-bp160.1.1 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms