---
title: "GitHub"
description: "Use github.com and GitHub Enterprise Server: issues, pull requests, discussions, notifications, Actions, checks, releases and webhooks."
canonical_url: "https://forgeslink-3mwmle35v-poetry.vercel.app/providers/github"
---
# GitHub

> Use github.com and GitHub Enterprise Server: issues, pull requests, discussions, notifications, Actions, checks, releases and webhooks.

The GitHub provider works with github.com and GitHub Enterprise Server. It can read and write issues, pull requests, discussions and commit comments, and it also covers notifications, Actions runs and jobs, checks, releases, security alerts, webhooks and GitHub App installations.

<provider-header provider="github">
<table>
<thead>
  <tr>
    <th>
      Detail
    </th>
    
    <th>
      Value
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Import
    </td>
    
    <td>
      <code>
        forges/github
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Factories
    </td>
    
    <td>
      <code>
        github()
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Auth
    </td>
    
    <td>
      <code>
        token
      </code>
      
      , <code>
        app
      </code>
      
      , <code>
        anonymous
      </code>
    </td>
  </tr>
</tbody>
</table>
</provider-header>

## Authentication

The provider accepts a personal access token (classic or fine-grained), an OAuth token or the credentials of a GitHub App:

```ts
import { github } from 'forges/github'

const forge = github({
  auth: { type: 'token', token: process.env.GITHUB_TOKEN! },
})

const app = github({
  auth: {
    type: 'app',
    appId: 123456,
    privateKey: process.env.GITHUB_APP_PRIVATE_KEY!,
    installationId: 7890,
  },
})
```

For app authentication, `privateKey` is the PEM key of the app, in PKCS#1 or PKCS#8 format. If you pass an `installationId` as well, the provider acts as that installation, and it creates and caches installation tokens whenever it needs one. If you leave it out, the provider authenticates as the app itself. In that case, `installations.list()` lists the installations of the app, and `installations.provider(installation)` gives you a provider for one of them.

If you leave out `auth` altogether, the provider makes anonymous reads of public data. GitHub serves job logs and code search only to authenticated requests, so `ci.log` and `search.code` aren't supported without `auth`.

An app without an `installationId` can only use `installations`, so every other capability is unsupported for it.

What a token can do depends on its kind, which the provider reads from the token's prefix:

<table>
<thead>
  <tr>
    <th>
      <code>
        kind
      </code>
    </th>
    
    <th>
      Prefix
    </th>
    
    <th>
      Token
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        classic
      </code>
    </td>
    
    <td>
      <code>
        ghp_
      </code>
      
      , <code>
        gho_
      </code>
    </td>
    
    <td>
      A personal access token (classic) or an OAuth app token
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fine-grained
      </code>
    </td>
    
    <td>
      <code>
        github_pat_
      </code>
    </td>
    
    <td>
      A fine-grained personal access token
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        app-user
      </code>
    </td>
    
    <td>
      <code>
        ghu_
      </code>
    </td>
    
    <td>
      A GitHub App user access token
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        installation
      </code>
    </td>
    
    <td>
      <code>
        ghs_
      </code>
    </td>
    
    <td>
      A GitHub App installation access token, such as the <code>
        GITHUB_TOKEN
      </code>
      
       of a workflow
    </td>
  </tr>
</tbody>
</table>

If `token` is a function, pass `kind` as well, or the provider assumes that the token can do anything a token can:

```ts
const forge = github({
  auth: { type: 'token', token: () => refreshUserToken(), kind: 'app-user' },
})
```

GitHub serves notifications only to `classic` tokens, so `notifications` is unsupported for every other kind and for app authentication. `users.me()` needs a token that belongs to an account, so it isn't supported for an `installation` token or an app installation.

## Sponsors

`users.sponsorable(login)` reports whether a user or organisation has a GitHub Sponsors listing, so you can link to `https://github.com/sponsors/<login>` when it does:

```ts
if (await forge.users.sponsorable('danielroe')) {
  console.log('https://github.com/sponsors/danielroe')
}
```

GitHub reports Sponsors listings only over GraphQL, which needs a token or an app installation, so `users.sponsorable` isn't supported without `auth`. GitHub Enterprise Server doesn't have GitHub Sponsors, so it isn't supported there either.

## GitHub Enterprise Server

To use GitHub Enterprise Server, set `baseUrl` to the API root of your server. The `instance` in every ref is then the host of the server:

```ts
github({
  baseUrl: 'https://ghe.example.com/api/v3',
  auth,
  instanceVersion: '3.14.0',
})
```

Two capabilities depend on the version of the server. Marking notifications as done requires version 3.13 or later, and Dependabot alerts require version 3.8 or later. If you know the version, pass it as `instanceVersion`. If you don't, `refreshCapabilities()` reads it from `/meta`.

## Listing pull requests

GitHub lists pull requests in full pages. When you filter by label, author, assignee or `since`, though, the provider can't use that listing and reads the pull requests from GitHub's issues listing instead, which mixes issues and pull requests. The provider drops the issues, so a page can contain fewer items than `perPage`. To list merged pull requests, the provider uses GitHub's search API, which has a lower rate limit and can lag a little behind the repository. See [Page through results](https://forgeslink-3mwmle35v-poetry.vercel.app/guides/pagination) for how to deal with short pages.

## Listing an owner's repositories

With `visibility: 'public'`, `repos.byOwner()` lists the repositories of a user or an organisation in a single request. For any other visibility, it reads the repositories of an organisation first. When no organisation has that name, it reads the repositories of the user instead, so listing a user's repositories costs one more request. For the authenticated user, that includes private repositories. GitHub lists only the public repositories of other users, so for them, `visibility: 'private'` or `'internal'` returns an empty page with a `filter_unsupported` warning.

## Contributors

GitHub groups commits by account and links only the first 500 author emails in a repository to accounts; the rest come back with a `name` and an `email` but no `actor`. `repos.contributors()` leaves those unlinked contributors out, as GitHub's own listing does, so a count taken from the default listing runs low for a repository with more than 500 author emails; pass `includeUnlinked: true` to include them. GitHub does not list the contributors of a repository whose history or contributor list is too large, and its contributor data can be a few hours old.

## Contributor statistics

GitHub computes the statistics behind `repos.contributorStats()` in the background, and responds with `202 Accepted` until they are ready. The provider asks again for about 15 seconds, and then throws a `ForgeApiError` with status `202`, so you can try again later. The statistics leave out merge commits and empty commits. In a repository with 10,000 or more commits, GitHub reports `0` lines added and deleted for every week.

## Templates

`repos.templates()` reads the folders GitHub reads: `.github/ISSUE_TEMPLATE/` for issues, forms first and then Markdown templates, as in the template chooser, and `.github/`, the root or `docs/` for the pull request template, first match wins. Every file in a `PULL_REQUEST_TEMPLATE/` folder comes after it. It's one request per folder and one per template.

When a repository has nothing of a kind, the templates come from the `.github` repository of its owner, like on the web, and carry it in `source`. That is the owner the repository lives under now, so a transferred repository gets the templates of its new owner. The provider uses a `.github` repository only while it is public, or internal, as GitHub does, which costs one more request. A lone `config.yml` in `.github/ISSUE_TEMPLATE/` still counts as having issue templates, so GitHub skips the fallback, and so does the provider. If reading the `.github` repository fails for any reason other than a `404`, `repos.templates()` rejects.

The provider returns each file as it is, so `body` is the raw file, `name` is the file name, and `title`, `about`, `labels` and `fields` stay empty. Parse the front matter or the form in `body` for the name GitHub shows.

## Merging

If you call `merge()` without a `method`, the provider asks GitHub which merge methods the repository allows. When exactly one method is allowed, it uses that one. When several are allowed, it can't choose for you and throws `MergeMethodRequiredError`.

`merge()` requests a direct merge through GitHub's asynchronous merge API, which means that it doesn't add the pull request to a merge queue. It waits for GitHub to report the result, within the `timeout` of the provider (30 seconds by default), and resolves with the merge commit once the pull request is merged. That includes a pull request that was already merged. In every other case, it rejects with one of these errors:

- `MergeBlockedError` when GitHub refuses or fails the merge, for example because of a draft, a failing required check or a pull request that is already in a merge queue. If GitHub reports a failed merge, the message of the error is GitHub's description of the failure.
- `MergeConflictError` when GitHub responds with a conflict status that doesn't name a pending merge request.
- `ForgeTimeoutError` when the merge is still pending after `timeout`. The message includes the UUID of the merge request. GitHub can still complete the merge after this error, so read the state of the pull request before you try again.

If a direct merge with the same method is already pending, and it expects the same head sha when you pass `sha`, the operation waits for that request instead of starting a new one. A pending request with different options rejects with `MergeBlockedError`. Passing a `title` or a `message` also prevents the provider from adopting a pending request, because GitHub doesn't return the commit title or message of a request.

When the pull request is part of a stack, GitHub also merges every open pull request below it in the stack. GitHub Enterprise Server releases without the asynchronous merge API use the synchronous merge endpoint instead, and that endpoint doesn't support stacked pull requests.

Two options aren't available, and they reject with `UnsupportedOperationError`. One is `whenChecksPass`, because the REST API doesn't enable auto-merge. The other is the `rebase_merge` and `fast_forward_only` methods, which GitHub doesn't have.

## Updating a branch

`updateBranch()` merges the base branch into the head branch through the REST API, which takes no method, and rebases through GraphQL with `method: 'rebase'`. GitHub checks `sha` against the head as it updates, and rejects with `BranchMovedError` when the head has moved. GitHub updates the branch in the background, so `updateBranch()` resolves with `status: 'queued'`. Read the pull request later to see the new head.

## Closing references

`closingIssues()` and `closingPullRequests()` read through GraphQL, so they need a credential. They list the issues that a closing keyword such as `Fixes #1` names, and the ones linked to the pull request by hand. `closingPullRequests()` lists closed and merged pull requests too.

## Review threads

`reviewThreads()` reads the conversations through GraphQL, up to 100 a page, each with its first 100 comments. When the code under a conversation changes, GitHub marks it outdated and can leave it without a line on the current diff, so `outdated` is `true` and `line` and `startLine` fall back to the lines the comments were written on. `reviews()` and `getReview()` also read every page of conversations through GraphQL, to find the `thread` of each comment. GraphQL needs a token, so an anonymous provider can't list conversations.

## Review replies

GitHub doesn't support replies to replies, so when you pass a reply to `replyToReviewComment()`, it posts to the comment in its `inReplyTo` instead. The new comment carries the `thread` of the comment you pass, so you can call `resolveReviewThread()` with it.

## Checks

What `checks.report()` writes depends on your credential. With the credential of an app installation, it writes a check run, and with any other credential it writes a commit status. `checks.rerun()` re-requests a check run, so it can't re-run a commit status. Only the app that created a check run can re-request it, so for a check run that GitHub Actions created, `checks.rerun()` re-runs its job instead, which needs the `actions: write` permission on a GitHub App. A check run that another app created is rejected with a `ForbiddenError` whose `reason` is `not_owner`. Such a check run has `run`, the workflow run that it's a job of, so you can re-run every failed job of that run with `ci.rerunFailed(check.run)`.

`threads.get()`, `threads.getMany()`, `threads.list()` and `threads.closingPullRequests()` read the check runs and commit statuses of each pull request into `checks`, so on a GitHub App they need the `checks: read` and `statuses: read` permissions.

## Branch rules

GitHub keeps two kinds of rules for a branch: rulesets and classic branch protection. `repos.branchRules()` reads both and merges them, so you don't have to care which one the maintainer clicked. A check that both ask for is listed once, with the app that either of them names, and when both ask for approvals, the higher count wins.

The catch is classic protection. Anyone who can read the repository sees its required checks, but GitHub shows its approval count only to an admin. It responds to other accounts with `404`, and to a GitHub App without `administration: read` with `403`. Without credentials, the provider doesn't ask. Without admin access, or `administration: read` on a GitHub App, `requiredApprovals` holds only what the rulesets ask for, or is absent when no ruleset asks, and the result carries an `insufficient_scope` warning. Treat that number as the floor, not the whole answer.

## Security advisories

With `kind: 'advisory'`, `securityAlerts.list()` lists the security advisories of the repository, including the drafts and private vulnerability reports that the credential can see. Those need a security manager, an administrator, or a collaborator on the advisory. A report in triage or a draft is `open`, a published advisory is `fixed`, and a closed or withdrawn one is `dismissed`. For `open` and `closed`, the provider reads every advisory and keeps those in that state, so a page can hold fewer than `perPage`. GitHub Enterprise Server doesn't list advisories.

## Large files and trees

Files over 1 MB are read through the Git blobs API, so the result of `contents.getFile()` has `encoding: 'none'` for them. When GitHub truncates a large tree, `contents.tree()` adds a `tree_truncated` warning to the result.

On github.com, `contents.getFile()` with `metadata: false` reads the file from `raw.githubusercontent.com`, whose requests don't count towards the REST API rate limit. The result has no `sha` or `url`. That host caches a file for up to five minutes, so a read of a branch can lag behind a push to it. A commit sha as `ref` avoids that. It responds with 404 to a revoked or expired token too, so the read rejects with a `NotFoundError` rather than a `TokenRevokedError`. On GitHub Enterprise Server and `ghe.com`, `metadata: false` has no effect.

## Comparisons

Without `commitLimit`, `contents.compare()` returns the newest 250 commits of the comparison. GitHub pages a comparison from its oldest commit, so with `commitLimit`, the provider reads the first page, and then the last pages, which hold the newest commits. Each page holds `commitLimit` commits, up to 100. A comparison that fits on the first page takes one request. GitHub always sends the changed files with the first page, up to 300 of them, so `files: false` leaves them out of the result but not out of the response.

## Committing files

Without `author`, `contents.commitFiles()` makes the commit with one GraphQL `createCommitOnBranch` mutation, so GitHub signs it and attributes it to the account of the credential. With `author`, the provider writes the commit through the Git database API instead, and moves the branch with the GraphQL `updateRefs` mutation, which checks that the branch is still where the change started. GitHub doesn't sign that commit, and it records `author` as the committer too.

Without `author`, `createFrom` creates the branch before the commit. If the commit fails, the provider deletes the branch again, unless it has moved since.

A file keeps its mode when you write over it: an executable file stays executable, and a symlink stays a symlink, pointing at the new contents.

## Search

GitHub gives search a lower rate limit than the rest of its API, and code search has a limit of its own, separate from the search for issues, commits and repositories. After a search, `page.rateLimit` reports the limit that the search used, and its `resource` names it, such as `search` or `code_search`. `rateLimits()` and `onRateLimit` keep it apart from the `core` budget of the rest of the API.

Repository search can't sort by creation time. If you ask for that order, you get the results by relevance, together with a `sort_unsupported` warning.

When you call `search.threads()` without a `kind`, it uses GitHub's advanced search to return issues and pull requests in a single sorted list. `text` and `queryRaw` are each wrapped in parentheses, so an `OR` in one of them stays inside it. Parentheses and an unclosed `"` in `text` are ignored, in the same way that GitHub's legacy search ignores them. On GitHub Enterprise Server, or with a GitHub App user access token (`ghu_`), the provider searches issues first and pull requests after that instead, so the results are only sorted within each kind.

`queryRaw` is added to the search query as it is, which means you can use any [GitHub search qualifier](https://docs.github.com/search-github/searching-on-github):

```ts
const page = await gh.search.threads({ kind: 'pull_request', queryRaw: 'review-requested:@me' }).page()
```

To search every repository of a user or an organisation, pass `owner`. The provider sends it as the `user:` qualifier, which matches organisations as well as users. If you also pass `repo`, the provider ignores `owner`:

```ts
const page = await gh.search.threads({ owner: 'nuxt', text: 'hydration' }).page()
```

`search.code()` gets the tightest limit of all: 10 requests a minute, in a pool of its own. It only sees the default branch, and only files under 384 KB. Each result is a file, with `ref` set to the commit that GitHub indexed. `fragments` holds the excerpts that GitHub highlighted. They have no line numbers, because GitHub doesn't send any. When GitHub stops a search before it finishes, the page has a `search_incomplete` warning.

## GraphQL

For what the data model doesn't cover, a GitHub provider has `graphql()`, which sends a query or mutation to the GraphQL API of its instance with the provider's credentials. It resolves with the `data` of the response. When the response carries errors, it rejects with a `ForgeApiError`, with an `InsufficientScopeError` when the token lacks a scope that a field needs, or with a `RateLimitedError` for a rate limit, which GitHub reports with a `200`:

```ts
const { viewer } = await forge.graphql<{ viewer: { login: string } }>(
  'query { viewer { login } }',
)
```

To have the result and the variables typed for you, pass a typed document instead of a string. [GraphQL Code Generator](https://the-guild.dev/graphql/codegen) creates them from GitHub's [public schema](https://docs.github.com/public/fpt/schema.docs.graphql) with its client preset and `documentMode: 'string'`, in `codegen.ts`:

```ts
import type { CodegenConfig } from '@graphql-codegen/cli'

export default {
  schema: 'https://docs.github.com/public/fpt/schema.docs.graphql',
  documents: ['src/**/*.ts'],
  generates: {
    './src/gql/': { preset: 'client', config: { documentMode: 'string' } },
  },
} satisfies CodegenConfig
```

The result of `graphql()` then has the type of the document's selection, and the variables that the document requires must be passed:

```ts
import { graphql } from './gql'

const Stars = graphql(`
  query Stars($owner: String!, $name: String!) {
    repository(owner: $owner, name: $name) { stargazerCount }
  }
`)

const { repository } = await forge.graphql(Stars, { owner: 'danielroe', name: 'forges' })
```

A read-only provider runs queries and rejects mutations with `ReadOnlyError`. GitHub's GraphQL API needs a credential, so an anonymous provider can't use it. Accounts in the data model carry the numeric ID, which GraphQL calls `databaseId`, so select that field to compare them with your results.

## Activity feeds

`repos.events()` and `users.events()` read GitHub's events API. A feed holds up to 300 events from the last 30 days, and GitHub can take from 30 seconds to 6 hours to add an event to it. Events come in the order GitHub added them, so an event that arrived late can follow one that happened after it. When the credential belongs to the account you read, `users.events()` includes its private activity too.

GitHub asks clients to wait between reads of a feed, usually 60 seconds, in its `X-Poll-Interval` header. The provider remembers that wait for each feed. If you read the first page of a feed again before it's over, you get a page with `throttled: true` and no items, and no request is sent. The page keeps the `etag` you passed and carries a `feed_throttled` warning. A throttled feed and a quiet one both yield nothing from `events()`, so the warning is the only way to tell them apart:

```ts
const events = gh.repos.events(repo)
for await (const event of events) {
  console.log(event.summary)
}
if (events.warnings.some(warning => warning.code === 'feed_throttled')) {
  // too soon, not empty
}
```

To read anyway, pass `force: true`:

```ts
const page = await gh.repos.events(repo, { force: true }).page()
```

The provider only remembers the wait for as long as it exists, so a job that creates a new provider for every run isn't held back. Such a job can keep the `nextPollAt` of the page it read, which says when GitHub allows the next read, and schedule its next run for then.

`notifications.list()` follows the same rules, with one wait for the whole notifications listing, and takes `force: true` as well.

Feed items are smaller than webhook deliveries. On GitHub.com, a push has no commits and no commit count, so its `detail` has no `commitCount` and its summary leaves the number out. GitHub Enterprise Server still sends both, and they fill in the detail there. A pull request event has no title, and GitHub reports a merge as the action `merged`, which the provider reads as `kind: 'state_change'` and `action: 'merged'`.

## Webhook management

If the credential lacks `admin:repo_hook` or `admin:org_hook`, GitHub responds with a `404` on its webhook endpoints. The provider raises this response as a `ForbiddenError` with `reason: 'resource_protected'`, so check the scopes of your credential when you see it.

`webhooks.deliveries()` reads the delivery log of a hook, and `webhooks.redeliver()` sends a delivery again.

## Webhooks

To verify deliveries, set `webhookSecret` to the secret that you configured on the hook:

```ts
const forge = github({
  webhookSecret: process.env.GITHUB_WEBHOOK_SECRET,
})

const events = await forge.webhooks.ingest({
  headers: request.headers,
  body: await request.text(),
})
```

With each delivery, GitHub sends these headers:

<table>
<thead>
  <tr>
    <th>
      Header
    </th>
    
    <th>
      Content
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        X-Hub-Signature-256
      </code>
    </td>
    
    <td>
      <code>
        sha256=
      </code>
      
       followed by the hex HMAC-SHA256 of the body
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        X-GitHub-Event
      </code>
    </td>
    
    <td>
      The event name
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        X-GitHub-Delivery
      </code>
    </td>
    
    <td>
      The delivery ID
    </td>
  </tr>
</tbody>
</table>

Deliveries of the `installation` and `installation_repositories` events become `installation` events.

## Moderation

`threads.lock()` locks an issue or pull request through REST, with the reason GitHub shows on the thread, and a discussion through GraphQL. GitHub refuses a reason for a discussion, so the provider leaves `reason` out. `threads.hideComment()` minimises a comment through GraphQL, with the reason as its classifier. It works on comments on issues, pull requests and discussions, but not on inline review comments. `commits.hideComment()` does the same for a comment on a commit.

`orgs.block()` blocks an account from the organisation and needs the `admin:org` scope, or the `organization_user_blocking` write permission. `users.block()` blocks it for the account the token belongs to, so it needs a user token with the `user` scope, or the `blocking` write permission; `can('users.block')` is `false` for a GitHub App installation. A repeat can reject with a `ForgeApiError` with `status` 422.

## Issue types

An organisation defines its issue types, and its repositories inherit them. `repos.issueTypes()` reads the types enabled for a repository with `GET /repos/{owner}/{repo}/issue-types`. It needs a credential, because GitHub responds to an anonymous request with 404. The `id` of an `IssueType` is its node ID, and its `colour` is one of GitHub's named colours, such as `red`. An issue that you read through REST, GraphQL or a webhook delivery carries its type as `thread.issueType`.

`threads.setIssueType()` sets a type by name, or clears it with `undefined`. When the token cannot push to the repository, GitHub leaves the type as it was and still responds with 200, so compare the result with the type that you asked for. Deliveries of `issues` with the actions `typed` and `untyped` become `issue_type` events. GitHub Enterprise Server doesn't document the listing or these deliveries, so `can('repos.issueTypes')` is `false` there.

## Organisation teams

`orgs.teams()` reads the teams of an organisation with `GET /orgs/{org}/teams`, and `orgs.teamMembers()` reads `GET /orgs/{org}/teams/{slug}/members`. Both need a token with the `read:org` scope, or the `members` read permission on a fine-grained token, so `can('orgs.teams')` is `false` without a credential. A team's members include the members of its child teams.

## Capabilities

<provider-capabilities provider="github">
<table>
<thead>
  <tr>
    <th>
      Capability
    </th>
    
    <th>
      Classic token
    </th>
    
    <th>
      Fine-grained token
    </th>
    
    <th>
      App installation
    </th>
    
    <th>
      App
    </th>
    
    <th>
      Without credentials
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        experimental
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sources.stream
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.get
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        users.get
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        users.me
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        users.sponsorable
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        users.events
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        users.block
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.list
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.byOwner
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.labels
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.createLabel
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.milestones
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.issueTypes
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.collaborators
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.contributors
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.contributorStats
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.templates
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.permissionFor
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.branchRules
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.addCollaborator
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.assignableUsers
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.reviewerCandidates
      </code>
    </td>
    
    <td>
      emulated
    </td>
    
    <td>
      emulated
    </td>
    
    <td>
      emulated
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.events
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        orgs.teams
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        orgs.teamMembers
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        orgs.block
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.get
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      issue, PR
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.list
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      issue, PR
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.getMany
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.closingIssues
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.closingPullRequests
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.events
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      issue, PR
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.comments
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      issue, PR
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.getComment
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      issue (unverified), PR
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.createComment
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.updateComment
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.deleteComment
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.hideComment
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.reactions
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      issue, PR
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.react
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.create
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.update
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.close
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.reopen
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.lock
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.setLabels
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.addLabels
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.removeLabels
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.setMilestone
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.setIssueType
      </code>
    </td>
    
    <td>
      issue
    </td>
    
    <td>
      issue
    </td>
    
    <td>
      issue
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.setAssignees
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.requestReview
      </code>
    </td>
    
    <td>
      PR
    </td>
    
    <td>
      PR
    </td>
    
    <td>
      PR
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.merge
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.updateBranch
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.transfer
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.markDuplicate
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.subscription
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.subscribe
      </code>
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      issue, PR, discussion
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.checks
      </code>
    </td>
    
    <td>
      PR
    </td>
    
    <td>
      PR
    </td>
    
    <td>
      PR
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      PR
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.files
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.commits
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.reviews
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.getReview
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      unverified
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.createReview
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.submitReview
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.approve
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.replyToReviewComment
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.reviewThreads
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.resolveReviewThread
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notifications.list
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notifications.markRead
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notifications.markDone
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notifications.unsubscribe
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notifications.markAllRead
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notifications.markAllDone
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notifications.unreadCount
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        installations.list
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        checks.list
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        checks.get
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        checks.report
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        checks.rerun
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ci.runs
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ci.getRun
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ci.jobs
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ci.getJob
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ci.log
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ci.rerunFailed
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.getFile
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.tree
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.branches
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.tags
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.resolveRef
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.compare
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.commitFiles
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        commits.list
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        commits.get
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        commits.comments
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        commits.getComment
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      unverified
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        commits.createComment
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        commits.updateComment
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        commits.deleteComment
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        commits.hideComment
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        releases.list
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        releases.get
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        releases.latest
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        releases.getByTag
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        releases.downloadAsset
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        releases.create
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        releases.update
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.ingest
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.list
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.create
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.update
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.delete
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.rotateSecret
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.deliveries
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.redeliver
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        search.threads
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        search.repos
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        search.commits
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        search.code
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        securityAlerts.list
      </code>
    </td>
    
    <td>
      dependency, code scanning, secret, advisory
    </td>
    
    <td>
      dependency, code scanning, secret, advisory
    </td>
    
    <td>
      dependency, code scanning, secret, advisory
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        eventKinds
      </code>
    </td>
    
    <td>
      native
    </td>
    
    <td>
      native
    </td>
    
    <td>
      native
    </td>
    
    <td>
      native
    </td>
    
    <td>
      native
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        authKinds
      </code>
    </td>
    
    <td>
      <code>
        token
      </code>
      
      , <code>
        app
      </code>
      
      , <code>
        anonymous
      </code>
    </td>
    
    <td>
      <code>
        token
      </code>
      
      , <code>
        app
      </code>
      
      , <code>
        anonymous
      </code>
    </td>
    
    <td>
      <code>
        token
      </code>
      
      , <code>
        app
      </code>
      
      , <code>
        anonymous
      </code>
    </td>
    
    <td>
      <code>
        token
      </code>
      
      , <code>
        app
      </code>
      
      , <code>
        anonymous
      </code>
    </td>
    
    <td>
      <code>
        token
      </code>
      
      , <code>
        app
      </code>
      
      , <code>
        anonymous
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        limits
      </code>
    </td>
    
    <td>
      body 65536, comment 65536, label 50
    </td>
    
    <td>
      body 65536, comment 65536, label 50
    </td>
    
    <td>
      body 65536, comment 65536, label 50
    </td>
    
    <td>
      body 65536, comment 65536, label 50
    </td>
    
    <td>
      body 65536, comment 65536, label 50
    </td>
  </tr>
</tbody>
</table>

Support depends on the kind of credential:

- `classic` (Classic token): A personal access token (classic) or an OAuth app token
- `fine-grained` (Fine-grained token): A fine-grained personal access token or a GitHub App user access token
- `installation` (App installation): An app with an `installationId`, or an installation access token such as the `GITHUB_TOKEN` of a workflow
- `app` (App): An app without an `installationId`

</provider-capabilities>


## Sitemap

See the full [sitemap](https://forgeslink-3mwmle35v-poetry.vercel.app/sitemap.md) for all pages.
