Home / Alt manpages / gh-api(1)

  • gh-api(1)
  • User command
  • linux

Query GitHub safely with gh api, then make deliberate changes

You will use GitHub CLI's gh api to make authenticated requests, inspect JSON, filter useful fields and submit a controlled payload. Allow 15 minutes for a first read-only query, or longer if you are testing a write against a disposable issue or repository. The examples assume Linux, GitHub CLI 2.87.3, an account that can access the target data and an existing gh login.

Checkpoint

This guide starts with read-only requests. A request with parameters becomes POST by default, so pause before copying any command that contains -f or -F.

1. Check the installed command and authentication

Confirm which executable will run and check the CLI version. The command's API authentication comes from its normal GitHub CLI configuration, or from GH_TOKEN and related environment variables. Do not paste a token into a shell command, a script committed to a repository or a support transcript.

$ command -v gh
/usr/bin/gh
$ gh --version
gh version 2.87.3 (2026-02-23)
$ gh auth status

The final command should identify an authenticated account and the relevant host. If it reports that you are not logged in, run gh auth login interactively and complete that separate flow. No request has been made by these checks.

2. Read a repository endpoint

Pass an API v3 path without the leading site URL. The placeholders {owner}, {repo} and {branch} are filled from the repository in your current directory. If you are outside a checkout, provide a literal owner and repository, or set GH_REPO. Quote the endpoint in shells that give braces special meaning.

$ gh api 'repos/{owner}/{repo}/releases'
[
  {
    "url": "https://api.github.com/repos/OWNER/REPO/releases/RELEASE_ID",
    "tag_name": "..."
  }
]

The response is JSON and will vary with the repository. An HTTP or authentication error is printed by gh and the command exits unsuccessfully; check the endpoint, host and account permissions before retrying.

3. Select fields without hand-editing JSON

Use --jq when you need a small, script-friendly result. This example prints release names only. The filter is evaluated locally after the response arrives.

$ gh api 'repos/{owner}/{repo}/releases' --jq '.[].tag_name'
v2.87.3
v2.87.2

Those values are examples of the shape, not a promise about a repository's current releases. Use --template when Go template formatting is more convenient. Keep the default JSON when another program needs the complete response.

4. Add query parameters while staying read-only

Adding either field flag normally changes the request to POST. For a search query, override that behaviour explicitly with --method GET. -f sends a string; -F performs type conversion for true, false, null, integers, repository placeholders and file values.

$ gh api --method GET search/issues \
    -f 'q=repo:cli/cli is:open remote' \
    --jq '.items[].title'

Checkpoint

Before running a field-bearing command, make sure the method is visible and intentional. If you omit --method GET, the installed CLI selects POST, which is wrong for this search and may be rejected by the endpoint.

5. Send a JSON body deliberately

For an endpoint that expects a pre-built body, keep the JSON in a file and pass it with --input. A filename is easier to review than a long shell-quoted payload. This example changes an issue, so replace the placeholder values only after checking the repository and issue number.

$ printf '%s\n' '{"body":"Status checked from the CLI"}' > /tmp/gh-issue-comment.json
$ gh api --method POST \
    'repos/OWNER/REPO/issues/123/comments' \
    --input /tmp/gh-issue-comment.json \
    --jq '.html_url'

The output should be the URL of the newly created comment if the request succeeds. This is an external, potentially irreversible action: verify OWNER, REPO and 123 first, and do not use a real issue merely to test authentication. Remove the temporary body after checking it with sed -n '1p' /tmp/gh-issue-comment.json; never delete a source file that supplied a payload by mistake.

6. Read payload values from files and build nested data

With -F, a value beginning with @ reads the remainder as a filename. @- reads standard input. Square brackets express nested objects and arrays, which is useful for endpoints that accept structured form fields.

$ gh api gists \
    -F 'description=Short review note' \
    -F 'public=false' \
    -F 'files[notes.txt][content][email protected]'

This creates a gist, so treat it as a write. The literal false is sent as JSON false with -F, while the file content is read from notes.txt. Check the path and the destination before running it. There is no general undo command in gh api; use the created resource's documented delete endpoint or GitHub web interface if you need to remove it.

7. Handle pagination and GraphQL

Use --paginate when one response may contain more pages. For REST endpoints, the CLI follows the endpoint's pagination links. Each page is emitted separately. The installed CLI also supports --slurp to wrap paginated JSON arrays or objects in an outer array, which can make later processing easier.

$ gh api --paginate 'user/repos?per_page=100' \
    --jq '.[].full_name'

For GraphQL, use the literal endpoint graphql. A paginated query must declare an $endCursor: String variable and request pageInfo with hasNextPage and endCursor. Fields other than query and operationName become GraphQL variables.

$ gh api graphql \
    -F owner='{owner}' -F name='{repo}' \
    -f query='query($owner:String!, $name:String!) {
      repository(owner:$owner, name:$name) { nameWithOwner }
    }' \
    --jq '.data.repository.nameWithOwner'

8. Diagnose without changing state

Use --include when the status line and response headers will explain a failure, or --verbose when you need the full request and response. Treat verbose output as sensitive: headers can reveal tokens or other credentials in some environments, so redact it before storing or sharing it. --silent suppresses the response body but does not turn a write into a dry run.

$ gh api --include 'repos/OWNER/REPO' | sed -n '1,12p'
$ gh api --hostname github.example.com 'repos/OWNER/REPO' --jq '.full_name'

Use --hostname for an enterprise host, or set the corresponding host configuration before the request. A successful exit status means the HTTP request completed successfully; still inspect the selected field or returned status before treating the operation as complete.

Done means

  • gh --version and gh auth status identify the installed client and usable account.
  • Read-only requests use a clear endpoint and, when fields are present, an explicit --method GET.
  • --jq, templates or pagination are used only when their output shape is understood.
  • Every write has a reviewed owner, repository, endpoint, payload and method.
  • Temporary payloads and diagnostic output contain no credentials, and any created resource has a documented recovery path.