---
title: "Forgejo and Codeberg"
description: "Use Codeberg and self-hosted Forgejo instances: issues, pull requests, notifications, releases and webhooks."
canonical_url: "https://forges.link/providers/forgejo"
---
# Forgejo and Codeberg

> Use Codeberg and self-hosted Forgejo instances: issues, pull requests, notifications, releases and webhooks.

The Forgejo provider works with Codeberg and self-hosted Forgejo instances. It can read and write issues and pull requests, and it also covers notifications, commit statuses, releases, repository contents and the webhooks of repositories and organisations. The [Gitea](https://forges.link/providers/gitea) provider uses the same implementation.

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

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

## Authentication

The provider accepts an access token. If you use an OAuth2 application on Forgejo, the user tokens that it issues work too, and you pass them in the same way:

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

const forge = forgejo({
  auth: { type: 'token', token: process.env.CODEBERG_TOKEN! },
}).create()
```

If you leave out `auth`, the provider makes anonymous reads of public data.

## Instance

The default instance is `https://codeberg.org`. To use a self-hosted instance, set `baseUrl` to the root of the instance. The provider appends `/api/v1` itself:

```ts
forgejo({ baseUrl: 'https://git.example.com', auth })
```

`refreshCapabilities()` reads the version of the instance from `/version`.

## Marking notifications done

Forgejo notifications have a read state but no done state. To give you `markDone()` anyway, the provider emulates it, which is why it is `'emulated'` in the capabilities. It marks the notification as read, so it leaves the unread listing, and you stay subscribed to the thread. A later change to the thread brings the notification back as unread. To stop those notifications as well, call `unsubscribe()`.

## Merging

If you call `merge()` without a `method`, the provider reads the merge styles that the repository allows. When exactly one style is allowed, it uses that one. When several are allowed, it throws `MergeMethodRequiredError`. If you pass `whenChecksPass`, Forgejo merges the pull request after its checks succeed.

The merge response has no body, so `merge()` resolves without a `sha`. Its `status` is `'queued'` when Forgejo schedules the merge until the checks pass, and `'merged'` otherwise. Read the pull request to see the merge commit.

The head branch stays after `merge()`, even when `deleteBranchOnMerge` is `true`, because Forgejo applies that setting only in its web interface. Gitea did the same before 1.25.

## Reviews

Forgejo supports reviews natively. `createReview()` without an `event` creates a pending review, and `submitReview()` submits it. The API doesn't expose whether a review conversation is resolved, so `resolveReviewThread()` isn't available. The API has no endpoint to reply to a review comment either, so `replyToReviewComment()` isn't available.

## Checks and CI

`checks.list()` reads commit statuses, and `checks.report()` writes them. `checks.rerun()` isn't available.

The `ci` methods read Forgejo Actions. Runs need Forgejo 12 or later, and jobs and job logs need Forgejo 16. Codeberg runs a current release, so they work there out of the box. For a self-hosted instance, pass `instanceVersion` or call `refreshCapabilities()` first.

Forgejo before 15 ignores the branch filter, so `ci.runs()` drops the runs of other branches itself, and a page can come back shorter than `perPage`. Forgejo doesn't page the jobs of a run, so `ci.jobs()` returns all of them in one page.

## Changed files

`threads.files()` and `contents.compare()` return line counts for each file, but they don't return a `patch`. Forgejo serves diffs only for a whole pull request.

With `files: false`, `contents.compare()` asks Forgejo to leave out the changed files of each commit. Forgejo always sends every commit of a comparison, so the provider keeps the newest `commitLimit` of them itself.

## Committing files

Forgejo can't check the head of a branch as it commits, so with `expectedHead`, `contents.commitFiles()` reads the branch first and rejects with `BranchMovedError` when it has moved. A commit that lands between the two requests isn't caught. With `createFrom`, the provider creates the branch before the commit. If the commit fails, the provider deletes the branch again, unless it has moved since. Forgejo records `author` as the committer too.

Forgejo refuses to write over a symlink, so a change with contents for one rejects with a `422` `ForgeApiError`. Deleting a symlink works.

## Templates

Issue templates come from Forgejo's API, which parses `title`, `about`, `labels` and the `fields` of a form. The provider reads each file once more for `body`, with its front matter or the YAML of the form.

Pull request templates come from the files themselves. The provider picks the one file the web UI would fill a new pull request with: `PULL_REQUEST_TEMPLATE` or `pull_request_template`, as `.md`, `.yaml` or `.yml`, in the root, `.forgejo/`, `.gitea/`, `.github/` or `docs/`, in that order. Gitea looks only in the root, `.gitea/` and `.github/`. The provider takes the first file that exists without validating it, while the web UI skips a template it can't parse and tries the next.

## Listing an owner's repositories

`repos.byOwner()` reads the repositories of a user or an organisation from the same listing, oldest first. Forgejo can't filter or sort that listing, so the provider filters by `visibility` itself, and if you ask for any other order, you get a `sort_unsupported` warning.

## Activity feeds

Forgejo serves activity feeds from version 1.20. `users.events()` lists only what the account did, not what others did in its repositories. Forgejo sends no `etag` with a feed, so polling one always reads the whole page.

A release in a feed has its title but not its ID, so its event has `kind: 'release'` and no `detail`.

## Search

`search.threads()` searches across repositories. It has no `involves` filter, and it returns the results newest first, whatever `sort` or `direction` you pass. If you pass `involves`, you get a `filter_unsupported` warning, and if you pass a `sort` other than `relevance`, you get a `sort_unsupported` warning.

## Webhooks

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

```ts
const forge = forgejo({
  webhookSecret: process.env.FORGEJO_WEBHOOK_SECRET,
}).create()

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

With each delivery, Forgejo sends these headers:

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

<tbody>
  <tr>
    <td>
      <code>
        X-Forgejo-Signature
      </code>
    </td>
    
    <td>
      The hex HMAC-SHA256 of the body
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        X-Forgejo-Event
      </code>
    </td>
    
    <td>
      The event name
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        X-Forgejo-Delivery
      </code>
    </td>
    
    <td>
      The delivery ID
    </td>
  </tr>
</tbody>
</table>

The provider also accepts the `X-Gitea-*` version of each header.

A label delivery doesn't say which labels were added or removed. When the set of labels changes, the provider reports a `label` event with the `edited` action, and when every label is removed, a `label` event with the `unlabelled` action.

`webhooks.deliveries()` and `webhooks.redeliver()` aren't available.

## Organisation teams

`orgs.teams()` reads `GET /orgs/{org}/teams`, and `orgs.teamMembers()` reads the members of one team. Forgejo addresses a team's members by id, so the provider reads `GET /teams/{id}/members` with the ref's `id`. For a ref with only a `slug`, it first resolves the slug (a team's name) to its id with the teams listing. Both need a token with the `read:organization` scope, and Forgejo responds with a 403 when the account isn't a member of the organisation. A slug that names no team rejects with `NotFoundError`.

## Capabilities

<provider-capabilities provider="forgejo">
<table>
<thead>
  <tr>
    <th>
      Capability
    </th>
    
    <th>
      Support
    </th>
    
    <th>
      Without credentials
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        experimental
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sources.poll
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sources.webhook
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sources.subscribe
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.get
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        users.get
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        users.me
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        users.sponsorable
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        users.events
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.list
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.byOwner
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.labels
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.createLabel
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.milestones
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.collaborators
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.contributors
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.contributorStats
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.templates
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.permissionFor
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.addCollaborator
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.assignableUsers
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.reviewerCandidates
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        repos.events
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        orgs.teams
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        orgs.teamMembers
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.get
      </code>
    </td>
    
    <td>
      issue, PR, commit
    </td>
    
    <td>
      issue, PR, commit
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.list
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.getMany
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threads.events
      </code>
    </td>
    
    <td>
      issue, PR, commit
    </td>
    
    <td>
      issue, PR, commit
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        comments.list
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        comments.get
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        comments.edit
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        comments.delete
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reactions.list
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      issue, PR
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notifications.list
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notifications.markRead
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notifications.markDone
      </code>
    </td>
    
    <td>
      emulated
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notifications.unsubscribe
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notifications.markAllRead
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notifications.markAllDone
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        notifications.unreadCount
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.comment
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.upsertComment
      </code>
    </td>
    
    <td>
      issue (emulated), PR (emulated)
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.close
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.reopen
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.create
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.update
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.setLabels
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.addLabels
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.removeLabels
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.setMilestone
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.react
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.setAssignees
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.requestReview
      </code>
    </td>
    
    <td>
      PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.merge
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.approveAndMerge
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.transfer
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        writes.markDuplicate
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        subscriptions.get
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        subscriptions.set
      </code>
    </td>
    
    <td>
      issue, PR
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        installations
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        checks.thread
      </code>
    </td>
    
    <td>
      PR
    </td>
    
    <td>
      PR
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        checks.list
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        checks.get
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        checks.report
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        checks.rerun
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ci.runs
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ci.run
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ci.jobs
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ci.job
      </code>
    </td>
    
    <td>
      emulated
    </td>
    
    <td>
      emulated
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ci.log
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.file
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.tree
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.branches
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.tags
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.resolveRef
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.commits
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.commit
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.compare
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.commitFiles
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.threadFiles
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contents.threadCommits
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reviews.list
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reviews.get
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reviews.create
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reviews.submit
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reviews.approve
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reviews.reply
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reviews.resolveThread
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        releases.list
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        releases.get
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        releases.latest
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        releases.getByTag
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        releases.downloadAsset
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        releases.create
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        releases.update
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.list
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.create
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.update
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.delete
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.rotateSecret
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.deliveries
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        webhooks.redeliver
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        search.threads
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        search.repos
      </code>
    </td>
    
    <td>
      ✅
    </td>
    
    <td>
      ✅
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        search.commits
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        search.code
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        securityAlerts
      </code>
    </td>
    
    <td>
      ❌
    </td>
    
    <td>
      ❌
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        eventKinds
      </code>
    </td>
    
    <td>
      native
    </td>
    
    <td>
      native
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        authKinds
      </code>
    </td>
    
    <td>
      <code>
        token
      </code>
      
      , <code>
        anonymous
      </code>
    </td>
    
    <td>
      <code>
        token
      </code>
      
      , <code>
        anonymous
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        limits
      </code>
    </td>
    
    <td>
      unknown
    </td>
    
    <td>
      unknown
    </td>
  </tr>
</tbody>
</table>
</provider-capabilities>


## Sitemap

See the full [sitemap](https://forges.link/sitemap.md) for all pages.
