# REST API reference

> Every REST API endpoint with its parameters, access rules and an example, generated from the server's router.

Source: https://diffinery.com/docs/api

Every endpoint of the Diffinery REST API, generated from the server's router, so this list always matches what `https://diffinery.com/api/v3` serves. The same information is available as an [OpenAPI 3.1 document](https://diffinery.com/docs/api/openapi.json). For authentication, errors, pagination and GitHub compatibility, read the [REST API guide](https://diffinery.com/docs/reference/rest-api).

## Basics

- Base URL: `https://diffinery.com/api/v3`
- Authenticate with a personal access token: `Authorization: Bearer dfy_...` (`token dfy_...` and HTTP Basic with the token as the password work too). Create one under *Settings → Access tokens*.
- Send and receive JSON. Errors are JSON objects with a `message` and a `documentation_url`, unknown paths included (404).
- Reads of public repositories need no token. Every write needs a signed-in caller (401 otherwise) and, from a token, the `write` scope (403 otherwise). A token's scope also caps its role on a repository: `read` reads, `write` acts up to maintain, `admin` acts as admin. Each endpoint below says which scope it needs.
- A private repository you can't see is a 404, whatever the method, so a read token's write to it doesn't reveal that it exists.
- An archived repository refuses every write with 403 `repository is archived (read-only)`, except unarchiving it (`PATCH` with `archived: false`), deleting it and watching it.
- A workflow job's `GITHUB_TOKEN` follows the job's `permissions:` instead of token scopes: each endpoint needs its permission (`contents`, `issues`, `pull-requests`, `actions` and so on), and settings, secrets, variables, webhooks and branch protection are out of its reach. See [Workflow permissions](https://diffinery.com/docs/actions/workflow-permissions).
- Paths, field names and status codes follow GitHub's REST API wherever Diffinery has the same feature, so most GitHub clients work with `baseUrl` set to the URL above.
- 452 endpoints in 29 groups.

## Endpoints by group

- [Meta](#meta) (3)
- [Users](#users) (6)
- [Organizations](#organizations) (12)
- [Search](#search) (2)
- [Repositories](#repositories) (19)
- [Contents](#contents) (12)
- [Releases](#releases) (15)
- [Git database](#git-database) (15)
- [Branches and tags](#branches-and-tags) (4)
- [Commit statuses](#commit-statuses) (5)
- [Checks](#checks) (8)
- [Commits](#commits) (5)
- [Branch protection](#branch-protection) (3)
- [Issues](#issues) (38)
- [Pull requests](#pull-requests) (29)
- [Merge queue](#merge-queue) (3)
- [Deployments](#deployments) (6)
- [Environments](#environments) (16)
- [Actions secrets and variables](#actions-secrets-and-variables) (22)
- [Actions artifacts and caches](#actions-artifacts-and-caches) (9)
- [Actions](#actions) (26)
- [Webhooks](#webhooks) (3)
- [Packages](#packages) (22)
- [Imports](#imports) (15)
- [Status page](#status-page) (4)
- [Notifications and email](#notifications-and-email) (27)
- [Tokens and agents](#tokens-and-agents) (8)
- [Sandboxes](#sandboxes) (2)
- [Other](#other) (113)

## Meta

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/` | [API root](#api-root) |
| GET | `/meta` | [Instance metadata](#instance-metadata) |
| GET | `/rate_limit` | [Get rate limit status](#get-rate-limit-status) |

### API root

```http
GET /api/v3
```

Names the API and links to these docs and the MCP endpoint.

**Access:** No authentication needed.

```sh
curl "https://diffinery.com/api/v3"
```

### Instance metadata

```http
GET /api/v3/meta
```

Whether this instance issues OIDC tokens to workflows, and the runner image its last deploy set (`runner_image`; each job reports the image it ran on as `runner.image`), and whether it tells search engines about changed public pages through IndexNow (`indexnow`: `enabled`, `key_location` and the time, URL count, IndexNow status and `endpoint` of the `last_submission`; see [Site administration](https://diffinery.com/docs/admin/site-administration#search-engines)).

**Access:** No authentication needed.

```sh
curl "https://diffinery.com/api/v3/meta"
```

### Get rate limit status

```http
GET /api/v3/rate_limit
```

For GitHub clients that check their budget before calling. It always reports a full, constant budget (15000 core requests an hour). Diffinery's real limits are per minute (2,000 requests per account, 60 new repositories, issues, pull requests, comments and the like, 300 requests per IP address without signing in) and answer 429 with `retry-after: 60`; see /docs/reference/rest-api#rate-limits.

**Access:** No authentication needed.

```sh
curl "https://diffinery.com/api/v3/rate_limit"
```

## Users

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/user` | [Get the authenticated account](#get-the-authenticated-account) |
| PUT | `/user/avatar` | [Set your profile picture](#set-your-profile-picture) |
| DELETE | `/user/avatar` | [Remove your profile picture](#remove-your-profile-picture) |
| GET | `/user/orgs` | [List your organizations](#list-your-organizations) |
| POST | `/user/orgs` | [Create an organization](#create-an-organization) |
| GET | `/users/{login}` | [Get an account](#get-an-account) |

### Get the authenticated account

```http
GET /api/v3/user
```

Returns your account, including `email` and `site_admin`. Agents get their own account (type `Bot`).

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/user" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Set your profile picture

```http
PUT /api/v3/user/avatar
```

Diffinery only. The raw request body is the image (JPEG, PNG or WebP, at most 5 MB), not JSON. Returns the new `avatar_url`. A token needs `write` or `admin` scope and must not be limited to repositories. Audited.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories.

```sh
curl -X PUT "https://diffinery.com/api/v3/user/avatar" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Remove your profile picture

```http
DELETE /api/v3/user/avatar
```

Diffinery only. Goes back to generated initials and returns the `avatar_url`. Same token rules as setting one. Audited.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories.

```sh
curl -X DELETE "https://diffinery.com/api/v3/user/avatar" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List your organizations

```http
GET /api/v3/user/orgs
```

Each organization carries your `role` in it (member, admin or owner).

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/user/orgs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create an organization

```http
POST /api/v3/user/orgs
```

**Access:** Any active account (a token, or a browser session). Tokens need the `admin` scope and access to all repositories. **Success:** `201`.

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `login` | string | yes | Organization login (letters, digits, `-` and `_`; no dots). |
| `name` | string | no | Display name (default: the login). |

```sh
curl -X POST "https://diffinery.com/api/v3/user/orgs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"login":"..."}'
```

### Get an account

```http
GET /api/v3/users/{login}
```

A user, organization or agent by login. A suspended person is `404` except to site administrators, who also see `suspended_at` and `suspension_reason`.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `login` | string | yes | Account login. |

```sh
curl "https://diffinery.com/api/v3/users/diffy" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Organizations

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/invitations` | [List pending invitations to this instance](#list-pending-invitations-to-this-instance) |
| POST | `/invitations` | [Invite someone to this instance](#invite-someone-to-this-instance) |
| DELETE | `/invitations/{id}` | [Revoke an invitation to this instance](#revoke-an-invitation-to-this-instance) |
| GET | `/orgs/{org}` | [Get an organization](#get-an-organization) |
| PATCH | `/orgs/{org}` | [Update an organization](#update-an-organization) |
| DELETE | `/orgs/{org}` | [Delete an organization](#delete-an-organization) |
| PUT | `/orgs/{org}/avatar` | [Set an organization's picture](#set-an-organizations-picture) |
| DELETE | `/orgs/{org}/avatar` | [Remove an organization's picture](#remove-an-organizations-picture) |
| GET | `/orgs/{org}/invitations` | [List an organization's pending invitations](#list-an-organizations-pending-invitations) |
| POST | `/orgs/{org}/invitations` | [Invite someone to an organization](#invite-someone-to-an-organization) |
| DELETE | `/orgs/{org}/invitations/{id}` | [Revoke an organization invitation](#revoke-an-organization-invitation) |
| GET | `/orgs/{org}/members` | [List organization members](#list-organization-members) |

### List pending invitations to this instance

```http
GET /api/v3/invitations
```

Site-wide invites only, not those to an organization or repository. Site admins only.

**Access:** A site administrator. Tokens need the `read` scope and access to all repositories.

```sh
curl "https://diffinery.com/api/v3/invitations" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Invite someone to this instance

```http
POST /api/v3/invitations
```

A site-wide invite with no organization. Site admins only.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories. **Success:** `201`.

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string | yes | Email address to invite. |

```sh
curl -X POST "https://diffinery.com/api/v3/invitations" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email":"..."}'
```

### Revoke an invitation to this instance

```http
DELETE /api/v3/invitations/{id}
```

Site admins only. 404 when no pending site-wide invitation has this id. Audited.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/invitations/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get an organization

```http
GET /api/v3/orgs/{org}
```

GitHub's organization object. Members, the organization's agents, agents of members, and site admins also get `default_repository_permission`, the organization's base permission (`none`, `read`, `write` or `admin`).

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update an organization

```http
PATCH /api/v3/orgs/{org}
```

Organization owners (and site admins) only; admins and members get 403. Returns the updated organization. Every field is checked before anything is saved, so a bad value (422) changes nothing. Changing the base permission applies to every member right away; owners and admins always keep admin. Audited.

**Access:** An owner of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `default_repository_permission` | string | no | Base permission every member gets on the organization's repositories: `none`, `read` (the default for new organizations), `write` or `admin`. |
| `name` | string | no | Display name. An empty value clears it, and pages show the login instead. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/orgs/acme" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete an organization

```http
DELETE /api/v3/orgs/{org}
```

Owners only (or site admins). Refused with 422 while the organization still owns repositories (transfer or delete them first), container images, or an import in progress. Its members, pending invitations, secrets and variables are removed, its agents disabled and their tokens revoked, and its login freed. Repositories transferred out of it keep redirecting from their old URLs. Audited. From a browser session whose sign-in is more than 2 hours old: 403 `Confirm it's you: sign in with your passkey again to do this.` with a `confirm` URL (see /docs/security/overview#confirming-its-you).

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories. **Success:** `202`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/orgs/acme" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Set an organization's picture

```http
PUT /api/v3/orgs/{org}/avatar
```

Diffinery only. Organization owners (and site admins) only. The raw request body is the image (JPEG, PNG or WebP, at most 5 MB), not JSON. Returns the new `avatar_url`. A token needs `write` or `admin` scope and must not be limited to repositories. Audited.

**Access:** An owner of the organization (or a site admin). Tokens need the `write` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

```sh
curl -X PUT "https://diffinery.com/api/v3/orgs/acme/avatar" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Remove an organization's picture

```http
DELETE /api/v3/orgs/{org}/avatar
```

Diffinery only. Organization owners (and site admins) only. Goes back to generated initials and returns the `avatar_url`. Audited.

**Access:** An owner of the organization (or a site admin). Tokens need the `write` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/orgs/acme/avatar" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List an organization's pending invitations

```http
GET /api/v3/orgs/{org}/invitations
```

Owners and admins (or site admins). Each has an `id` to revoke it with.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `read` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/invitations" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Invite someone to an organization

```http
POST /api/v3/orgs/{org}/invitations
```

Emails an invite link. The response holds the link too, so you can share it yourself. Refused with 422 when the address already has a pending invitation to the organization (letter case doesn't matter) or belongs to a member. You can send at most 50 invitations in 24 hours (site admins aren't limited); more answer 429 `you can send at most 50 invitations in 24 hours; try again later`.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string | yes | Email address to invite. |
| `role` | string | no | `member` (default), `admin` or `owner`. |

```sh
curl -X POST "https://diffinery.com/api/v3/orgs/acme/invitations" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"email":"..."}'
```

### Revoke an organization invitation

```http
DELETE /api/v3/orgs/{org}/invitations/{id}
```

The link stops working and the address can be invited again. 404 when no pending invitation has this id. Audited.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/orgs/acme/invitations/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List organization members

```http
GET /api/v3/orgs/{org}/members
```

Members only (or site admins). Each entry carries the member's `role`.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/members" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Search

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/search/issues` | [Search issues and pull requests](#search-issues-and-pull-requests) |
| GET | `/search/repositories` | [Search repositories](#search-repositories) |

### Search issues and pull requests

```http
GET /api/v3/search/issues
```

Searches the repositories you can read (only public ones without a token), at most 50 per query; `incomplete_results` is true when more were left out. Qualifiers: `repo:`, `user:`, `org:`, `owner:`, `is:`, `type:`, `state:`, `draft:`, `label:`, `no:`, `author:`, `assignee:`, `head:`, `base:`, `in:`, `created:`, `updated:`, `closed:` and `sort:`; others are searched as text. Only the first 1000 results are available, and every `score` is 1.

**Access:** No authentication needed.

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `q` | string | yes | Search query, at most 256 characters. |
| `sort` | string | no | `created` (default), `updated` or `comments`. |
| `order` | string | no | `desc` (default) or `asc`. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/search/issues"
```

### Search repositories

```http
GET /api/v3/search/repositories
```

Matches names, descriptions and topics of the repositories you can see (only public ones without a token). Qualifiers: `user:`, `org:`, `owner:`, `repo:`, `topic:`, `is:public`, `is:private`, `archived:` and `in:name,description,topics`. `fork:`, `language:`, `stars:`, `forks:`, `size:`, `pushed:` and `created:` are accepted but don't filter anything. Every `score` is 1.

**Access:** No authentication needed.

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `q` | string | yes | Search query, at most 256 characters. |
| `sort` | string | no | `updated` sorts by last push; anything else keeps the default order. |
| `order` | string | no | With `sort=updated`: `desc` (default) or `asc`. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/search/repositories"
```

## Repositories

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/orgs/{org}/repos` | [List an organization's repositories](#list-an-organizations-repositories) |
| POST | `/orgs/{org}/repos` | [Create an organization repository](#create-an-organization-repository) |
| GET | `/repos/{owner}/{repo}` | [Get a repository](#get-a-repository) |
| PATCH | `/repos/{owner}/{repo}` | [Update a repository](#update-a-repository) |
| DELETE | `/repos/{owner}/{repo}` | [Delete a repository](#delete-a-repository) |
| GET | `/repos/{owner}/{repo}/assignees` | [List assignable people](#list-assignable-people) |
| GET | `/repos/{owner}/{repo}/assignees/{login}` | [Check if someone can be assigned](#check-if-someone-can-be-assigned) |
| GET | `/repos/{owner}/{repo}/collaborators` | [List collaborators](#list-collaborators) |
| PUT | `/repos/{owner}/{repo}/collaborators/{login}` | [Invite a collaborator, or change one's role](#invite-a-collaborator-or-change-ones-role) |
| DELETE | `/repos/{owner}/{repo}/collaborators/{login}` | [Remove a collaborator](#remove-a-collaborator) |
| POST | `/repos/{owner}/{repo}/dispatches` | [Trigger a repository_dispatch event](#trigger-a-repository_dispatch-event) |
| GET | `/repos/{owner}/{repo}/invitations` | [List pending repository invitations](#list-pending-repository-invitations) |
| DELETE | `/repos/{owner}/{repo}/invitations/{id}` | [Revoke a repository invitation](#revoke-a-repository-invitation) |
| GET | `/repos/{owner}/{repo}/languages` | [List languages](#list-languages) |
| GET | `/repos/{owner}/{repo}/topics` | [Get topics](#get-topics) |
| PUT | `/repos/{owner}/{repo}/topics` | [Replace topics](#replace-topics) |
| GET | `/user/repos` | [List repositories you can access](#list-repositories-you-can-access) |
| POST | `/user/repos` | [Create a repository for yourself](#create-a-repository-for-yourself) |
| GET | `/users/{login}/repos` | [List an account's repositories](#list-an-accounts-repositories) |

### List an organization's repositories

```http
GET /api/v3/orgs/{org}/repos
```

Only the ones you can see. A token limited to repositories lists only those repositories.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/repos" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create an organization repository

```http
POST /api/v3/orgs/{org}/repos
```

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | Repository name. |
| `description` | string | no | Short description. |
| `visibility` | string | no | `private` (default) or `public`. |
| `default_branch` | string | no | Default branch name (default `main`). |

```sh
curl -X POST "https://diffinery.com/api/v3/orgs/acme/repos" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"..."}'
```

### Get a repository

```http
GET /api/v3/repos/{owner}/{repo}
```

Includes your role (`permissions.role`) and repository statistics.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update a repository

```http
PATCH /api/v3/repos/{owner}/{repo}
```

Works on an archived repository too, so an admin can unarchive it with `archived: false`. Audited as `repo.update`, `repo.archive` or `repo.unarchive`. A new `name` renames the repository: its old name keeps redirecting (see the transfer endpoint), until a repository is created there again. 422 when the owner already has a repository with that name.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | no | New name. |
| `description` | string | no | New description. |
| `visibility` | string | no | `private` or `public`. |
| `default_branch` | string | no | New default branch (must exist). |
| `archived` | boolean | no | Archive (read-only) or unarchive. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/repos/acme/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a repository

```http
DELETE /api/v3/repos/{owner}/{repo}
```

People only; agents can't delete repositories. Works on an archived repository too. Audited. From a browser session whose sign-in is more than 2 hours old: 403 `Confirm it's you: sign in with your passkey again to do this.` with a `confirm` URL (see /docs/security/overview#confirming-its-you).

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List assignable people

```http
GET /api/v3/repos/{owner}/{repo}/assignees
```

Collaborators with triage access or more, plus the owner when the owner is a user.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/assignees" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Check if someone can be assigned

```http
GET /api/v3/repos/{owner}/{repo}/assignees/{login}
```

204 when `login` is the repository's owner or a collaborator with triage access or more, 404 otherwise.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `login` | string | yes | Account login. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/assignees/diffy" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List collaborators

```http
GET /api/v3/repos/{owner}/{repo}/collaborators
```

Each entry carries `role_name`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/collaborators" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Invite a collaborator, or change one's role

```http
PUT /api/v3/repos/{owner}/{repo}/collaborators/{login}
```

As on GitHub, a person without access gets an invitation and has access once they accept it: the answer is `201` with the invitation (`id`, `repository`, `invitee`, `inviter`, `permissions`, `expires_at`), audited as `repo.invite`; asking again while it's pending changes its role. Agents, existing collaborators, members of the owning organization and yourself get the role at once: `204`, audited as `repo.collaborator.set`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `login` | string | yes | Account login. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `permission` | string | no | `read`, `triage`, `write` (default), `maintain` or `admin`; GitHub's `pull` and `push` work too. |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/collaborators/diffy" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Remove a collaborator

```http
DELETE /api/v3/repos/{owner}/{repo}/collaborators/{login}
```

Audited as `repo.collaborator.remove`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `login` | string | yes | Account login. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/collaborators/diffy" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Trigger a repository_dispatch event

```http
POST /api/v3/repos/{owner}/{repo}/dispatches
```

Starts workflows on the default branch that run `on: repository_dispatch` with this type, and sends the `repository_dispatch` webhook. Fails with 422 on an empty repository, and with 429 when the repository already has 500 unfinished workflow runs.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `event_type` | string | yes | Event type, at most 100 characters. |
| `client_payload` | object | no | Data for workflows as `github.event.client_payload`: at most 10 top-level keys and 64 KB. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/dispatches" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"event_type":"..."}'
```

### List pending repository invitations

```http
GET /api/v3/repos/{owner}/{repo}/invitations
```

Invitations sent by email to people without an account. Each has an `id` to revoke it with.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/invitations" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Revoke a repository invitation

```http
DELETE /api/v3/repos/{owner}/{repo}/invitations/{id}
```

The link stops working and the address can be invited again. 404 when no pending invitation to this repository has this id. Audited.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/invitations/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List languages

```http
GET /api/v3/repos/{owner}/{repo}/languages
```

Bytes of code per language on the default branch, largest first. Languages come from file extensions and a few well-known file names; vendored directories like `node_modules` and `vendor` are skipped.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/languages" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get topics

```http
GET /api/v3/repos/{owner}/{repo}/topics
```

Returns `{ names }`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/topics" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Replace topics

```http
PUT /api/v3/repos/{owner}/{repo}/topics
```

Names are lower-cased and deduplicated. Each starts with a letter or digit and has at most 50 letters, digits and dashes; at most 20 topics. Audited.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `names` | string[] | yes | Every topic the repository should have (`[]` clears them). |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/topics" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"names":["..."]}'
```

### List repositories you can access

```http
GET /api/v3/user/repos
```

A token limited to repositories lists only those repositories.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/user/repos" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a repository for yourself

```http
POST /api/v3/user/repos
```

An agent's repositories belong to its owner.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories. **Success:** `201`.

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | Repository name. |
| `description` | string | no | Short description. |
| `visibility` | string | no | `private` (default) or `public`. |
| `default_branch` | string | no | Default branch name (default `main`). |

```sh
curl -X POST "https://diffinery.com/api/v3/user/repos" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"..."}'
```

### List an account's repositories

```http
GET /api/v3/users/{login}/repos
```

Only the ones you can see. A token limited to repositories lists only those repositories.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `login` | string | yes | Account login. |

```sh
curl "https://diffinery.com/api/v3/users/diffy/repos" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Contents

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/repos/{owner}/{repo}/contents` | [List the root directory](#list-the-root-directory) |
| GET | `/repos/{owner}/{repo}/contents/{path}` | [Get a file or directory](#get-a-file-or-directory) |
| PUT | `/repos/{owner}/{repo}/contents/{path}` | [Create or update a file](#create-or-update-a-file) |
| DELETE | `/repos/{owner}/{repo}/contents/{path}` | [Delete a file](#delete-a-file) |
| POST | `/repos/{owner}/{repo}/diffinery/commits` | [Commit several files at once](#commit-several-files-at-once) |
| GET | `/repos/{owner}/{repo}/raw/{ref}/{path}` | [Download a raw file](#download-a-raw-file) |
| GET | `/repos/{owner}/{repo}/readme` | [Get the README](#get-the-readme) |
| GET | `/repos/{owner}/{repo}/readme/{dir}` | [Get a directory's README](#get-a-directorys-readme) |
| GET | `/repos/{owner}/{repo}/tarball` | [Download a tarball](#download-a-tarball) |
| GET | `/repos/{owner}/{repo}/tarball/{ref}` | [Download a tarball of a ref](#download-a-tarball-of-a-ref) |
| GET | `/repos/{owner}/{repo}/zipball` | [Download a zip archive](#download-a-zip-archive) |
| GET | `/repos/{owner}/{repo}/zipball/{ref}` | [Download a zip archive of a ref](#download-a-zip-archive-of-a-ref) |

### List the root directory

```http
GET /api/v3/repos/{owner}/{repo}/contents
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `ref` | string | no | Branch, tag or commit (default: the default branch). |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/contents" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a file or directory

```http
GET /api/v3/repos/{owner}/{repo}/contents/{path}
```

A directory returns an array of entries; a file returns its content base64-encoded.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `path` | string | yes | Path inside the repository, or a ref name after `refs/`. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `ref` | string | no | Branch, tag or commit (default: the default branch). |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/contents/README.md" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create or update a file

```http
PUT /api/v3/repos/{owner}/{repo}/contents/{path}
```

Commits one file.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `path` | string | yes | Path inside the repository, or a ref name after `refs/`. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `message` | string | yes | Commit message. |
| `content` | string | yes | New content, base64-encoded. |
| `branch` | string | no | Branch to commit to (default: the default branch). |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/contents/README.md" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message":"...","content":"..."}'
```

### Delete a file

```http
DELETE /api/v3/repos/{owner}/{repo}/contents/{path}
```

**Access:** Write access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `path` | string | yes | Path inside the repository, or a ref name after `refs/`. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `message` | string | yes | Commit message. |
| `branch` | string | no | Branch to commit to (default: the default branch). |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/contents/README.md" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message":"..."}'
```

### Commit several files at once

```http
POST /api/v3/repos/{owner}/{repo}/diffinery/commits
```

Diffinery only. Writes and deletes any number of files in one commit, without a git client. Pass `expected_head_sha` to fail instead of racing another writer. Push protection scans the new content as it does for `git push`: content that looks like a credential is refused with 422 and audited as `api.blocked_secret`. A repository admin who is a person can commit it anyway with an `allow_secrets` reason, audited as `api.secret_bypassed` and emailed to the repository's admins.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `branch` | string | yes | Branch to commit to. |
| `message` | string | yes | Commit message. |
| `files` | array | yes | Changes: `{ path, content, encoding: "utf-8" \| "base64", mode: "100644" \| "100755" }` or `{ path, delete: true }`. |
| `base` | string | no | Create `branch` from this ref when it doesn't exist. |
| `expected_head_sha` | string | no | Fail with 409 if the branch has moved. |
| `allow_secrets` | string | no | Why a detected secret may be committed anyway (repository admins who are people; at most 200 characters are kept). |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/diffinery/commits" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"branch":"...","message":"...","files":[]}'
```

### Download a raw file

```http
GET /api/v3/repos/{owner}/{repo}/raw/{ref}/{path}
```

The file's bytes, served as text or `application/octet-stream`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `ref` | string | yes | Branch, tag or commit SHA. |
| `path` | string | yes | Path inside the repository, or a ref name after `refs/`. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/raw/main/README.md" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get the README

```http
GET /api/v3/repos/{owner}/{repo}/readme
```

The README in the root directory, base64-encoded like a file from the contents API. A Markdown README wins when there are several. Send `Accept: application/vnd.github.raw` for the raw bytes.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `ref` | string | no | Branch, tag or commit (default: the default branch). |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/readme" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a directory's README

```http
GET /api/v3/repos/{owner}/{repo}/readme/{dir}
```

Like the root README, for the directory `dir`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `dir` | string | yes | dir |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `ref` | string | no | Branch, tag or commit (default: the default branch). |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/readme/dir" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Download a tarball

```http
GET /api/v3/repos/{owner}/{repo}/tarball
```

A `.tar.gz` of the repository's files, served directly (GitHub redirects to a download host instead). Built once per commit, at most 20 new builds per repository per hour (429 after that); repositories with more than 24 MB of files can't be archived (413). Uses the default branch.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/tarball" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Download a tarball of a ref

```http
GET /api/v3/repos/{owner}/{repo}/tarball/{ref}
```

A `.tar.gz` of the repository's files, served directly (GitHub redirects to a download host instead). Built once per commit, at most 20 new builds per repository per hour (429 after that); repositories with more than 24 MB of files can't be archived (413).

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `ref` | string | yes | Branch, tag or commit SHA. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/tarball/main" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Download a zip archive

```http
GET /api/v3/repos/{owner}/{repo}/zipball
```

A `.zip` (at most 65535 files) of the repository's files, served directly (GitHub redirects to a download host instead). Built once per commit, at most 20 new builds per repository per hour (429 after that); repositories with more than 24 MB of files can't be archived (413). Uses the default branch.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/zipball" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Download a zip archive of a ref

```http
GET /api/v3/repos/{owner}/{repo}/zipball/{ref}
```

A `.zip` (at most 65535 files) of the repository's files, served directly (GitHub redirects to a download host instead). Built once per commit, at most 20 new builds per repository per hour (429 after that); repositories with more than 24 MB of files can't be archived (413).

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `ref` | string | yes | Branch, tag or commit SHA. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/zipball/main" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Releases

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/repos/{owner}/{repo}/releases` | [List releases](#list-releases) |
| POST | `/repos/{owner}/{repo}/releases` | [Create a release](#create-a-release) |
| GET | `/repos/{owner}/{repo}/releases/{id}` | [Get a release](#get-a-release) |
| PATCH | `/repos/{owner}/{repo}/releases/{id}` | [Update a release](#update-a-release) |
| DELETE | `/repos/{owner}/{repo}/releases/{id}` | [Delete a release](#delete-a-release) |
| GET | `/repos/{owner}/{repo}/releases/{id}/assets` | [List release assets](#list-release-assets) |
| GET | `/repos/{owner}/{repo}/releases/{id}/reactions` | [List reactions to a release](#list-reactions-to-a-release) |
| POST | `/repos/{owner}/{repo}/releases/{id}/reactions` | [Add a reaction to a release](#add-a-reaction-to-a-release) |
| DELETE | `/repos/{owner}/{repo}/releases/{id}/reactions/{reaction}` | [Delete a reaction from a release](#delete-a-reaction-from-a-release) |
| GET | `/repos/{owner}/{repo}/releases/assets/{id}` | [Get a release asset](#get-a-release-asset) |
| PATCH | `/repos/{owner}/{repo}/releases/assets/{id}` | [Update a release asset](#update-a-release-asset) |
| DELETE | `/repos/{owner}/{repo}/releases/assets/{id}` | [Delete a release asset](#delete-a-release-asset) |
| POST | `/repos/{owner}/{repo}/releases/generate-notes` | [Generate release notes](#generate-release-notes) |
| GET | `/repos/{owner}/{repo}/releases/latest` | [Get the latest release](#get-the-latest-release) |
| GET | `/repos/{owner}/{repo}/releases/tags/{tag}` | [Get a release by tag](#get-a-release-by-tag) |

### List releases

```http
GET /api/v3/repos/{owner}/{repo}/releases
```

Newest first. Drafts are included only for people with write access.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/releases" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a release

```http
POST /api/v3/repos/{owner}/{repo}/releases
```

A published release (not a draft) creates its tag at `target_commitish` when the tag doesn't exist, sends `release` webhooks and starts `on: release` workflows; a draft only sends the `created` webhook. 422 when the tag already has a published release. Upload assets to the release's `upload_url`. `discussion_category_name` is ignored. See [Releases](https://diffinery.com/docs/collaboration/releases).

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `tag_name` | string | yes | Tag to release. |
| `target_commitish` | string | no | Branch, tag or commit for a new tag (default: the default branch). |
| `name` | string | no | Release title. |
| `body` | string | no | Markdown notes, at most 125000 characters. |
| `draft` | boolean | no | Save as a draft. |
| `prerelease` | boolean | no | Mark as a prerelease. |
| `make_latest` | string | no | `true` (default), `false`, or `legacy` (the newest by date). |
| `generate_release_notes` | boolean | no | Append generated notes to `body`. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/releases" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tag_name":"..."}'
```

### Get a release

```http
GET /api/v3/repos/{owner}/{repo}/releases/{id}
```

Drafts are 404 for people without write access.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/releases/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update a release

```http
PATCH /api/v3/repos/{owner}/{repo}/releases/{id}
```

Send only what changes. Setting `draft` to false publishes the release (creating its tag if needed); setting it back to true unpublishes it. Sends `release` webhooks.

**Access:** Write access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `tag_name` | string | no | New tag. |
| `target_commitish` | string | no | Branch, tag or commit for a new tag. |
| `name` | string | no | Release title. |
| `body` | string | no | Markdown notes, at most 125000 characters. |
| `draft` | boolean | no | Draft or published. |
| `prerelease` | boolean | no | Mark as a prerelease. |
| `make_latest` | string | no | `true`, `false` or `legacy`. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/repos/acme/website/releases/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a release

```http
DELETE /api/v3/repos/{owner}/{repo}/releases/{id}
```

Deletes its assets too; the tag stays. Sends the `release` webhook.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/releases/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List release assets

```http
GET /api/v3/repos/{owner}/{repo}/releases/{id}/assets
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/releases/1/assets" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List reactions to a release

```http
GET /api/v3/repos/{owner}/{repo}/releases/{id}/reactions
```

Drafts are hidden from people without write access, and so are their reactions.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `content` | string | no | Only reactions with this content. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/releases/1/reactions" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Add a reaction to a release

```http
POST /api/v3/repos/{owner}/{repo}/releases/{id}/reactions
```

Needs a signed-in account. Returns 201 for a new reaction, or 200 with the existing one when you had already reacted with that content.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `content` | string | yes | `+1`, `-1`, `laugh`, `confused`, `heart`, `hooray`, `rocket` or `eyes`. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/releases/1/reactions" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content":"..."}'
```

### Delete a reaction from a release

```http
DELETE /api/v3/repos/{owner}/{repo}/releases/{id}/reactions/{reaction}
```

Your own reactions, or anyone's with admin access.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |
| `reaction` | string | yes | reaction |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/releases/1/reactions/reaction" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a release asset

```http
GET /api/v3/repos/{owner}/{repo}/releases/assets/{id}
```

The asset's metadata, or the file itself with `Accept: application/octet-stream`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/releases/assets/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update a release asset

```http
PATCH /api/v3/repos/{owner}/{repo}/releases/assets/{id}
```

`state` is accepted and ignored.

**Access:** Write access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | no | New file name (unique within the release). |
| `label` | string | no | Display label. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/repos/acme/website/releases/assets/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a release asset

```http
DELETE /api/v3/repos/{owner}/{repo}/releases/assets/{id}
```

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/releases/assets/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Generate release notes

```http
POST /api/v3/repos/{owner}/{repo}/releases/generate-notes
```

Builds notes from the pull requests merged since the previous release, with categories from `.github/release.yml` (or `.yaml`). Nothing is saved; returns `{ name, body }`.

**Access:** Write access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `tag_name` | string | yes | Tag for the release. |
| `target_commitish` | string | no | Used when the tag doesn't exist yet (default: the default branch). |
| `previous_tag_name` | string | no | Start from this tag (default: the newest earlier published release). |
| `configuration_file_path` | string | no | Config file to use instead of `.github/release.yml`. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/releases/generate-notes" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tag_name":"..."}'
```

### Get the latest release

```http
GET /api/v3/repos/{owner}/{repo}/releases/latest
```

The release marked latest, or else the newest published release that isn't a prerelease. 404 when there is none.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/releases/latest" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a release by tag

```http
GET /api/v3/repos/{owner}/{repo}/releases/tags/{tag}
```

Published releases only; drafts aren't found by tag.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `tag` | string | yes | tag |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/releases/tags/tag" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Git database

| Method | Path | Summary |
| --- | --- | --- |
| POST | `/repos/{owner}/{repo}/git/blobs` | [Create a blob](#create-a-blob) |
| GET | `/repos/{owner}/{repo}/git/blobs/{sha}` | [Get a blob](#get-a-blob) |
| POST | `/repos/{owner}/{repo}/git/commits` | [Create a Git commit](#create-a-git-commit) |
| GET | `/repos/{owner}/{repo}/git/commits/{sha}` | [Get a Git commit](#get-a-git-commit) |
| GET | `/repos/{owner}/{repo}/git/matching-refs/{ref}` | [List matching references](#list-matching-references) |
| GET | `/repos/{owner}/{repo}/git/ref/{ref}` | [Get a reference](#get-a-reference) |
| GET | `/repos/{owner}/{repo}/git/refs` | [List all references](#list-all-references) |
| POST | `/repos/{owner}/{repo}/git/refs` | [Create a reference](#create-a-reference) |
| GET | `/repos/{owner}/{repo}/git/refs/{path}` | [List references](#list-references) |
| PATCH | `/repos/{owner}/{repo}/git/refs/{path}` | [Update a reference](#update-a-reference) |
| DELETE | `/repos/{owner}/{repo}/git/refs/{path}` | [Delete a reference](#delete-a-reference) |
| POST | `/repos/{owner}/{repo}/git/tags` | [Create a tag object](#create-a-tag-object) |
| GET | `/repos/{owner}/{repo}/git/tags/{sha}` | [Get a tag object](#get-a-tag-object) |
| POST | `/repos/{owner}/{repo}/git/trees` | [Create a tree](#create-a-tree) |
| GET | `/repos/{owner}/{repo}/git/trees/{sha}` | [Get a tree](#get-a-tree) |

### Create a blob

```http
POST /api/v3/repos/{owner}/{repo}/git/blobs
```

Push protection applies: content that looks like a credential is refused with 422. Returns `{ url, sha }`.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `content` | string | yes | The blob's content. |
| `encoding` | string | no | `utf-8` (default) or `base64`. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/git/blobs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content":"..."}'
```

### Get a blob

```http
GET /api/v3/repos/{owner}/{repo}/git/blobs/{sha}
```

Content is base64-encoded; send `Accept: application/vnd.github.raw` for the raw bytes.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `sha` | string | yes | sha |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/git/blobs/sha" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a Git commit

```http
POST /api/v3/repos/{owner}/{repo}/git/commits
```

Writes a commit object; no branch moves until you update a reference. `author` and `committer` default to you. Commits made by agents carry a `diffinery-agent` header.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `message` | string | yes | Commit message. |
| `tree` | string | yes | SHA of the commit's tree. |
| `parents` | string[] | no | Parent commit SHAs (none for a root commit). |
| `author` | object | no | `{ name, email, date }`. |
| `committer` | object | no | `{ name, email, date }` (default: the author). |
| `signature` | string | no | Signature to store in the commit as given. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/git/commits" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message":"...","tree":"..."}'
```

### Get a Git commit

```http
GET /api/v3/repos/{owner}/{repo}/git/commits/{sha}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `sha` | string | yes | sha |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/git/commits/sha" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List matching references

```http
GET /api/v3/repos/{owner}/{repo}/git/matching-refs/{ref}
```

Refs whose names start with `refs/{ref}`, like `heads/feature` or `tags/v1.`. Pull request refs appear only when `ref` starts with `pull/`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `ref` | string | yes | Branch, tag or commit SHA. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 100, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/git/matching-refs/main" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a reference

```http
GET /api/v3/repos/{owner}/{repo}/git/ref/{ref}
```

`ref` is the name after `refs/`, like `heads/main` or `tags/v1.0`, and must match exactly.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `ref` | string | yes | Branch, tag or commit SHA. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/git/ref/main" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List all references

```http
GET /api/v3/repos/{owner}/{repo}/git/refs
```

Every branch, tag and other ref, without pull request refs.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 100, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/git/refs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a reference

```http
POST /api/v3/repos/{owner}/{repo}/git/refs
```

Branch protection and agent rules apply as they do to a push.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `ref` | string | yes | Full ref name, like `refs/heads/feature`. |
| `sha` | string | yes | Commit to point at. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/git/refs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ref":"...","sha":"..."}'
```

### List references

```http
GET /api/v3/repos/{owner}/{repo}/git/refs/{path}
```

Every ref under `refs/{path}`, for example `heads` or `tags/v1`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `path` | string | yes | Path inside the repository, or a ref name after `refs/`. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/git/refs/README.md" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update a reference

```http
PATCH /api/v3/repos/{owner}/{repo}/git/refs/{path}
```

**Access:** Write access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `path` | string | yes | Path inside the repository, or a ref name after `refs/`. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `sha` | string | yes | New target commit. |
| `force` | boolean | no | Allow a non-fast-forward update. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/repos/acme/website/git/refs/README.md" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sha":"..."}'
```

### Delete a reference

```http
DELETE /api/v3/repos/{owner}/{repo}/git/refs/{path}
```

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `path` | string | yes | Path inside the repository, or a ref name after `refs/`. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/git/refs/README.md" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a tag object

```http
POST /api/v3/repos/{owner}/{repo}/git/tags
```

Writes an annotated tag object only; create its `refs/tags/...` reference with `POST /repos/{owner}/{repo}/git/refs` to publish it.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `tag` | string | yes | Tag name. |
| `object` | string | yes | SHA of the object to tag. |
| `message` | string | no | Tag message. |
| `type` | string | no | `commit`, `tree`, `blob` or `tag`; must match the object (default: its type). |
| `tagger` | object | no | `{ name, email, date }` (default: you). |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/git/tags" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tag":"...","object":"..."}'
```

### Get a tag object

```http
GET /api/v3/repos/{owner}/{repo}/git/tags/{sha}
```

`verification.verified` is always false.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `sha` | string | yes | sha |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/git/tags/sha" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a tree

```http
POST /api/v3/repos/{owner}/{repo}/git/trees
```

Applies the entries on top of `base_tree`. An entry with `content` creates a blob (push protection applies); one with `sha: null` deletes the path. `type` is ignored: the mode decides. At most 10000 entries per request.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `tree` | array | yes | Entries: `{ path, mode, sha }` or `{ path, mode, content }`. `mode` is `100644` (default), `100755`, `040000`, `160000` or `120000`. |
| `base_tree` | string | no | Tree to start from (default: an empty tree). |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/git/trees" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tree":[]}'
```

### Get a tree

```http
GET /api/v3/repos/{owner}/{repo}/git/trees/{sha}
```

`sha` may be a tree, a commit or a ref. `truncated` is true when a recursive listing stopped at 100000 entries.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `sha` | string | yes | sha |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `recursive` | string | no | Any value but `0` or `false` lists every entry below, not just the top level. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/git/trees/sha" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Branches and tags

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/repos/{owner}/{repo}/branches` | [List branches](#list-branches) |
| GET | `/repos/{owner}/{repo}/branches/{branch}` | [Get a branch](#get-a-branch) |
| POST | `/repos/{owner}/{repo}/merges` | [Merge a branch](#merge-a-branch) |
| GET | `/repos/{owner}/{repo}/tags` | [List tags](#list-tags) |

### List branches

```http
GET /api/v3/repos/{owner}/{repo}/branches
```

Each branch says whether it is `protected` and the `default`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/branches" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a branch

```http
GET /api/v3/repos/{owner}/{repo}/branches/{branch}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `branch` | string | yes | Branch name (for protection rules: a branch name or pattern). |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/branches/main" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Merge a branch

```http
POST /api/v3/repos/{owner}/{repo}/merges
```

Merges `head` into the `base` branch with a merge commit. Returns 201 with the commit, 204 when `base` already contains `head`, 409 on a conflict and 404 when either doesn't exist. Branch protection and agent rules apply as they do to a push.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `base` | string | yes | Branch to merge into. |
| `head` | string | yes | Branch, tag or commit to merge. |
| `commit_message` | string | no | Commit message (default: `Merge {head} into {base}`). |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/merges" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"base":"...","head":"..."}'
```

### List tags

```http
GET /api/v3/repos/{owner}/{repo}/tags
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/tags" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Commit statuses

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/repos/{owner}/{repo}/commits/{ref}/status` | [Get the combined status](#get-the-combined-status) |
| GET | `/repos/{owner}/{repo}/commits/{ref}/statuses` | [List commit statuses](#list-commit-statuses) |
| GET | `/repos/{owner}/{repo}/deployments/{id}/statuses/{status}` | [Get a deployment status](#get-a-deployment-status) |
| GET | `/repos/{owner}/{repo}/statuses/{ref}` | [List commit statuses for a ref](#list-commit-statuses-for-a-ref) |
| POST | `/repos/{owner}/{repo}/statuses/{sha}` | [Create a commit status](#create-a-commit-status) |

### Get the combined status

```http
GET /api/v3/repos/{owner}/{repo}/commits/{ref}/status
```

The latest status per context and an overall `state`: `failure` if any is `error` or `failure`, `pending` if any is pending or there are none, else `success`. Check runs aren't included.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `ref` | string | yes | Branch, tag or commit SHA. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Statuses per page (default 100, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/commits/main/status" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List commit statuses

```http
GET /api/v3/repos/{owner}/{repo}/commits/{ref}/statuses
```

Every status for the commit, newest first, including older ones for the same context.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `ref` | string | yes | Branch, tag or commit SHA. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/commits/main/statuses" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a deployment status

```http
GET /api/v3/repos/{owner}/{repo}/deployments/{id}/statuses/{status}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |
| `status` | string | yes | status |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/deployments/1/statuses/status" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List commit statuses for a ref

```http
GET /api/v3/repos/{owner}/{repo}/statuses/{ref}
```

Same as `GET /repos/{owner}/{repo}/commits/{ref}/statuses`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `ref` | string | yes | Branch, tag or commit SHA. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/statuses/main" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a commit status

```http
POST /api/v3/repos/{owner}/{repo}/statuses/{sha}
```

`sha` may also be a branch or tag. Statuses show with the checks, and a required check in branch protection can name a `context`; one account's status never replaces another's for that. At most 1000 statuses per commit and context. Sends the `status` webhook. See [Checks and statuses](https://diffinery.com/docs/collaboration/checks-and-statuses).

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `sha` | string | yes | sha |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | yes | `error`, `failure`, `pending` or `success`. |
| `target_url` | string | no | http(s) link to details. |
| `description` | string | no | Short description (cut at 1024 characters). |
| `context` | string | no | Label that tells statuses apart (default `default`). |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/statuses/sha" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"state":"..."}'
```

## Checks

| Method | Path | Summary |
| --- | --- | --- |
| POST | `/repos/{owner}/{repo}/check-runs` | [Create or update a check run](#create-or-update-a-check-run) |
| GET | `/repos/{owner}/{repo}/check-runs/{id}` | [Get a check run](#get-a-check-run) |
| PATCH | `/repos/{owner}/{repo}/check-runs/{id}` | [Update a check run](#update-a-check-run) |
| GET | `/repos/{owner}/{repo}/check-runs/{id}/annotations` | [List check run annotations](#list-check-run-annotations) |
| GET | `/repos/{owner}/{repo}/check-suites/{id}` | [Get a check suite](#get-a-check-suite) |
| GET | `/repos/{owner}/{repo}/check-suites/{id}/check-runs` | [List a check suite's check runs](#list-a-check-suites-check-runs) |
| GET | `/repos/{owner}/{repo}/commits/{ref}/check-runs` | [List check runs for a commit](#list-check-runs-for-a-commit) |
| GET | `/repos/{owner}/{repo}/commits/{ref}/check-suites` | [List check suites for a commit](#list-check-suites-for-a-commit) |

### Create or update a check run

```http
POST /api/v3/repos/{owner}/{repo}/check-runs
```

For external CI and integrations. A check with the same name on the same commit is updated. Required checks in branch protection can name it.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | Check name. |
| `head_sha` | string | yes | Commit the check is for. |
| `status` | string | no | `queued` (default), `in_progress` or `completed`. |
| `conclusion` | string | no | With `completed`: `success`, `failure`, `neutral`, `cancelled`, `skipped` or `timed_out`. |
| `details_url` | string | no | Link to more detail. |
| `output` | object | no | `{ title, summary }`. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/check-runs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"...","head_sha":"..."}'
```

### Get a check run

```http
GET /api/v3/repos/{owner}/{repo}/check-runs/{id}
```

`id` is the numeric id, Diffinery's own, or the id of the Actions job that reports it (a job's `check_run_url` points here).

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/check-runs/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update a check run

```http
PATCH /api/v3/repos/{owner}/{repo}/check-runs/{id}
```

Only the account that created the check run can update it, and runs from Diffinery Actions can't be changed. A `conclusion` completes the run. Annotations add to the existing ones (50 per request, 1000 in all).

**Access:** Write access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | no | New name. |
| `status` | string | no | `queued`, `in_progress`, `completed`, `waiting`, `requested` or `pending`. |
| `conclusion` | string | no | `action_required`, `cancelled`, `failure`, `neutral`, `success`, `skipped`, `stale` or `timed_out`. |
| `details_url` | string | no | http(s) link to more detail. |
| `external_id` | string | no | Your own reference for the run. |
| `started_at` | string | no | ISO timestamp. |
| `completed_at` | string | no | ISO timestamp. |
| `output` | object | no | `{ title, summary, text, annotations }`. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/repos/acme/website/check-runs/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List check run annotations

```http
GET /api/v3/repos/{owner}/{repo}/check-runs/{id}/annotations
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/check-runs/1/annotations" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a check suite

```http
GET /api/v3/repos/{owner}/{repo}/check-suites/{id}
```

`id` is a workflow run id or `app-{app}-{sha}`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/check-suites/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List a check suite's check runs

```http
GET /api/v3/repos/{owner}/{repo}/check-suites/{id}/check-runs
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/check-suites/1/check-runs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List check runs for a commit

```http
GET /api/v3/repos/{owner}/{repo}/commits/{ref}/check-runs
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `ref` | string | yes | Branch, tag or commit SHA. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/commits/main/check-runs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List check suites for a commit

```http
GET /api/v3/repos/{owner}/{repo}/commits/{ref}/check-suites
```

Diffinery derives check suites from check runs: one per workflow run, and one per app (id `app-{app}-{sha}`) for external check runs. `head_branch` is always null and `pull_requests` empty.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `ref` | string | yes | Branch, tag or commit SHA. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/commits/main/check-suites" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Commits

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/repos/{owner}/{repo}/commits` | [List commits](#list-commits) |
| GET | `/repos/{owner}/{repo}/commits/{ref}` | [Get a commit](#get-a-commit) |
| GET | `/repos/{owner}/{repo}/commits/{sha}/pulls` | [List pull requests for a commit](#list-pull-requests-for-a-commit) |
| GET | `/repos/{owner}/{repo}/compare/{spec}` | [Compare two refs](#compare-two-refs) |
| GET | `/repos/{owner}/{repo}/pulls/{number}/commits` | [List a pull request's commits](#list-a-pull-requests-commits) |

### List commits

```http
GET /api/v3/repos/{owner}/{repo}/commits
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `sha` | string | no | Branch, tag or commit to start from (default: the default branch). |
| `path` | string | no | Only commits that touch this path. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/commits" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a commit

```http
GET /api/v3/repos/{owner}/{repo}/commits/{ref}
```

The commit with its diff.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `ref` | string | yes | Branch, tag or commit SHA. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/commits/main" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List pull requests for a commit

```http
GET /api/v3/repos/{owner}/{repo}/commits/{sha}/pulls
```

Pull requests whose head or merge commit is this commit, plus open pull requests (the 50 newest) that contain it. 422 when the commit doesn't exist.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `sha` | string | yes | sha |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/commits/sha/pulls" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Compare two refs

```http
GET /api/v3/repos/{owner}/{repo}/compare/{spec}
```

`spec` is `base...head`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `spec` | string | yes | Two refs as `base...head`. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/compare/main...feature" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List a pull request's commits

```http
GET /api/v3/repos/{owner}/{repo}/pulls/{number}/commits
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/pulls/42/commits" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Branch protection

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/repos/{owner}/{repo}/branches/{branch}/protection` | [Get a protection rule](#get-a-protection-rule) |
| PUT | `/repos/{owner}/{repo}/branches/{branch}/protection` | [Create or replace a protection rule](#create-or-replace-a-protection-rule) |
| DELETE | `/repos/{owner}/{repo}/branches/{branch}/protection` | [Delete a protection rule](#delete-a-protection-rule) |

### Get a protection rule

```http
GET /api/v3/repos/{owner}/{repo}/branches/{branch}/protection
```

`branch` is the rule's pattern.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `branch` | string | yes | Branch name (for protection rules: a branch name or pattern). |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/branches/main/protection" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create or replace a protection rule

```http
PUT /api/v3/repos/{owner}/{repo}/branches/{branch}/protection
```

`branch` is a branch name or pattern. People only: agents and workflow tokens can't change protection. `allowAgentAutoMerge` (boolean) lets agents land pull requests through auto-merge or the merge queue; turning it on or off is audited as `repo.protection.agent_auto_merge`. `agentAutoMergeWithoutApproval` (boolean, needs `allowAgentAutoMerge`) lets those landings go through on green required checks without a person's approval, audited as `repo.protection.agent_approval_waiver`. `autoMergeAgents` (agent logins, needs `allowAgentAutoMerge`) has Diffinery turn auto-merge on by itself, as the agent, for pull requests those agents open, mark ready or push to, with `autoMergeMethod` (`merge`, `squash` or `rebase`) for how they merge; the answer stores them as `{ id, login }`, and changes are audited as `repo.protection.agent_auto_merge_rule`. See the branch protection guide for every field.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `branch` | string | yes | Branch name (for protection rules: a branch name or pattern). |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/branches/main/protection" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a protection rule

```http
DELETE /api/v3/repos/{owner}/{repo}/branches/{branch}/protection
```

Audited as `repo.protection.delete`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `branch` | string | yes | Branch name (for protection rules: a branch name or pattern). |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/branches/main/protection" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Issues

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/repos/{owner}/{repo}/issues` | [List issues and pull requests](#list-issues-and-pull-requests) |
| POST | `/repos/{owner}/{repo}/issues` | [Create an issue](#create-an-issue) |
| GET | `/repos/{owner}/{repo}/issues/{number}` | [Get an issue](#get-an-issue) |
| PATCH | `/repos/{owner}/{repo}/issues/{number}` | [Update an issue](#update-an-issue) |
| POST | `/repos/{owner}/{repo}/issues/{number}/assignees` | [Add assignees](#add-assignees) |
| DELETE | `/repos/{owner}/{repo}/issues/{number}/assignees` | [Remove assignees](#remove-assignees) |
| GET | `/repos/{owner}/{repo}/issues/{number}/comments` | [List comments](#list-comments) |
| POST | `/repos/{owner}/{repo}/issues/{number}/comments` | [Add a comment](#add-a-comment) |
| GET | `/repos/{owner}/{repo}/issues/{number}/events` | [List an issue's events](#list-an-issues-events) |
| GET | `/repos/{owner}/{repo}/issues/{number}/labels` | [List an issue's labels](#list-an-issues-labels) |
| POST | `/repos/{owner}/{repo}/issues/{number}/labels` | [Add labels to an issue](#add-labels-to-an-issue) |
| PUT | `/repos/{owner}/{repo}/issues/{number}/labels` | [Replace an issue's labels](#replace-an-issues-labels) |
| DELETE | `/repos/{owner}/{repo}/issues/{number}/labels` | [Remove all labels from an issue](#remove-all-labels-from-an-issue) |
| DELETE | `/repos/{owner}/{repo}/issues/{number}/labels/{name}` | [Remove a label from an issue](#remove-a-label-from-an-issue) |
| PUT | `/repos/{owner}/{repo}/issues/{number}/lock` | [Lock a conversation](#lock-a-conversation) |
| DELETE | `/repos/{owner}/{repo}/issues/{number}/lock` | [Unlock a conversation](#unlock-a-conversation) |
| GET | `/repos/{owner}/{repo}/issues/{number}/reactions` | [List reactions to an issue](#list-reactions-to-an-issue) |
| POST | `/repos/{owner}/{repo}/issues/{number}/reactions` | [Add a reaction to an issue](#add-a-reaction-to-an-issue) |
| DELETE | `/repos/{owner}/{repo}/issues/{number}/reactions/{reaction}` | [Delete a reaction from an issue](#delete-a-reaction-from-an-issue) |
| GET | `/repos/{owner}/{repo}/issues/{number}/timeline` | [List an issue's timeline](#list-an-issues-timeline) |
| GET | `/repos/{owner}/{repo}/issues/comments` | [List comments in a repository](#list-comments-in-a-repository) |
| GET | `/repos/{owner}/{repo}/issues/comments/{id}` | [Get a comment](#get-a-comment) |
| PATCH | `/repos/{owner}/{repo}/issues/comments/{id}` | [Edit a comment](#edit-a-comment) |
| DELETE | `/repos/{owner}/{repo}/issues/comments/{id}` | [Delete a comment](#delete-a-comment) |
| GET | `/repos/{owner}/{repo}/issues/comments/{id}/reactions` | [List reactions to a comment](#list-reactions-to-a-comment) |
| POST | `/repos/{owner}/{repo}/issues/comments/{id}/reactions` | [Add a reaction to a comment](#add-a-reaction-to-a-comment) |
| DELETE | `/repos/{owner}/{repo}/issues/comments/{id}/reactions/{reaction}` | [Delete a reaction from a comment](#delete-a-reaction-from-a-comment) |
| GET | `/repos/{owner}/{repo}/issues/events` | [List events in a repository](#list-events-in-a-repository) |
| GET | `/repos/{owner}/{repo}/issues/events/{id}` | [Get an event](#get-an-event) |
| GET | `/repos/{owner}/{repo}/labels` | [List labels](#list-labels) |
| POST | `/repos/{owner}/{repo}/labels` | [Create a label](#create-a-label) |
| GET | `/repos/{owner}/{repo}/labels/{name}` | [Get a label](#get-a-label) |
| PATCH | `/repos/{owner}/{repo}/labels/{name}` | [Update a label](#update-a-label) |
| DELETE | `/repos/{owner}/{repo}/labels/{name}` | [Delete a label](#delete-a-label) |
| GET | `/repos/{owner}/{repo}/milestones` | [List milestones](#list-milestones) |
| POST | `/repos/{owner}/{repo}/milestones` | [Create a milestone](#create-a-milestone) |
| GET | `/repos/{owner}/{repo}/milestones/{number}` | [Get a milestone](#get-a-milestone) |
| PATCH | `/repos/{owner}/{repo}/milestones/{number}` | [Update a milestone](#update-a-milestone) |

### List issues and pull requests

```http
GET /api/v3/repos/{owner}/{repo}/issues
```

As on GitHub, this list includes pull requests. The total is in the `X-Total-Count` header.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | no | `open` (default), `closed` or `all`. |
| `labels` | string | no | Only items with this label. |
| `creator` | string | no | Only items opened by this login. |
| `milestone` | string | no | A milestone number, `none` (no milestone) or `*` (any milestone). |
| `q` | string | no | Text search in titles. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/issues" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create an issue

```http
POST /api/v3/repos/{owner}/{repo}/issues
```

Needs a signed-in caller, also on a public repository. As on GitHub, `labels` and `assignees` from a caller without triage access are dropped without an error.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | yes | Title. |
| `body` | string | no | Markdown body. |
| `labels` | string[] | no | Label names. |
| `assignees` | string[] | no | Logins. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/issues" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"..."}'
```

### Get an issue

```http
GET /api/v3/repos/{owner}/{repo}/issues/{number}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/issues/42" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update an issue

```http
PATCH /api/v3/repos/{owner}/{repo}/issues/{number}
```

The author can edit their own issue or pull request. As on GitHub, `labels`, `assignees` and `milestone` from a caller without triage access are dropped without an error.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | no | New title. |
| `body` | string | no | New body. |
| `state` | string | no | `open` or `closed`. |
| `state_reason` | string | no | Why it was closed, like `completed` or `not_planned`. |
| `labels` | string[] | no | Replace the labels. |
| `assignees` | string[] | no | Replace the assignees. |
| `milestone` | integer | no | Milestone number, or `null` to remove the milestone. Ignored without triage access. Checked before anything is saved: 422 when it isn't a whole number or `null`, or when no milestone has that number. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/repos/acme/website/issues/42" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Add assignees

```http
POST /api/v3/repos/{owner}/{repo}/issues/{number}/assignees
```

Adds to the current assignees, at most 10 in all. Logins aren't checked against who can be assigned. Returns the issue.

**Access:** Triage access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `assignees` | string[] | no | Logins to add. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/issues/42/assignees" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Remove assignees

```http
DELETE /api/v3/repos/{owner}/{repo}/issues/{number}/assignees
```

Returns the issue.

**Access:** Triage access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `assignees` | string[] | no | Logins to remove. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/issues/42/assignees" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List comments

```http
GET /api/v3/repos/{owner}/{repo}/issues/{number}/comments
```

Conversation comments on an issue or pull request (not review comments).

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `since` | string | no | Only comments updated at or after this ISO timestamp. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/issues/42/comments" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Add a comment

```http
POST /api/v3/repos/{owner}/{repo}/issues/{number}/comments
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `body` | string | yes | Markdown body. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/issues/42/comments" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"body":"..."}'
```

### List an issue's events

```http
GET /api/v3/repos/{owner}/{repo}/issues/{number}/events
```

Labels, assignments, state changes, locks, review requests and the like, oldest first.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/issues/42/events" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List an issue's labels

```http
GET /api/v3/repos/{owner}/{repo}/issues/{number}/labels
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/issues/42/labels" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Add labels to an issue

```http
POST /api/v3/repos/{owner}/{repo}/issues/{number}/labels
```

Labels that don't exist yet are created. At most 100 per issue. Returns the issue's labels.

**Access:** Triage access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `labels` | string[] | yes | Label names (`{ name }` objects, or a bare array as the body, work too). |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/issues/42/labels" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"labels":["..."]}'
```

### Replace an issue's labels

```http
PUT /api/v3/repos/{owner}/{repo}/issues/{number}/labels
```

Labels that don't exist yet are created; `[]` removes them all. Returns the issue's labels.

**Access:** Triage access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `labels` | string[] | yes | Label names (`{ name }` objects, or a bare array as the body, work too). |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/issues/42/labels" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"labels":["..."]}'
```

### Remove all labels from an issue

```http
DELETE /api/v3/repos/{owner}/{repo}/issues/{number}/labels
```

**Access:** Triage access to the repository. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/issues/42/labels" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Remove a label from an issue

```http
DELETE /api/v3/repos/{owner}/{repo}/issues/{number}/labels/{name}
```

Returns the labels left. 404 when the issue doesn't have it.

**Access:** Triage access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |
| `name` | string | yes | Name. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/issues/42/labels/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Lock a conversation

```http
PUT /api/v3/repos/{owner}/{repo}/issues/{number}/lock
```

While locked, only people with triage access can comment, review or react.

**Access:** Triage access to the repository. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `lock_reason` | string | no | `off-topic`, `too heated`, `resolved` or `spam`. |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/issues/42/lock" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Unlock a conversation

```http
DELETE /api/v3/repos/{owner}/{repo}/issues/{number}/lock
```

**Access:** Triage access to the repository. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/issues/42/lock" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List reactions to an issue

```http
GET /api/v3/repos/{owner}/{repo}/issues/{number}/reactions
```

Works for pull requests too.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `content` | string | no | Only reactions with this content. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/issues/42/reactions" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Add a reaction to an issue

```http
POST /api/v3/repos/{owner}/{repo}/issues/{number}/reactions
```

Needs a signed-in account, and triage access when the conversation is locked. Returns 201 for a new reaction, or 200 with the existing one when you had already reacted with that content.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `content` | string | yes | `+1`, `-1`, `laugh`, `confused`, `heart`, `hooray`, `rocket` or `eyes`. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/issues/42/reactions" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content":"..."}'
```

### Delete a reaction from an issue

```http
DELETE /api/v3/repos/{owner}/{repo}/issues/{number}/reactions/{reaction}
```

Your own reactions, or anyone's with admin access.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |
| `reaction` | string | yes | reaction |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/issues/42/reactions/reaction" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List an issue's timeline

```http
GET /api/v3/repos/{owner}/{repo}/issues/{number}/timeline
```

Events, comments (`commented`) and reviews (`reviewed`) together, oldest first.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/issues/42/timeline" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List comments in a repository

```http
GET /api/v3/repos/{owner}/{repo}/issues/comments
```

Conversation comments on every issue and pull request.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `since` | string | no | Only comments updated at or after this ISO timestamp. |
| `sort` | string | no | `created` (default) or `updated`. |
| `direction` | string | no | `asc` (default) or `desc`. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/issues/comments" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a comment

```http
GET /api/v3/repos/{owner}/{repo}/issues/comments/{id}
```

`id` is the numeric id or Diffinery's own.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/issues/comments/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Edit a comment

```http
PATCH /api/v3/repos/{owner}/{repo}/issues/comments/{id}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `body` | string | yes | New Markdown body. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/repos/acme/website/issues/comments/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"body":"..."}'
```

### Delete a comment

```http
DELETE /api/v3/repos/{owner}/{repo}/issues/comments/{id}
```

Your own comments, or anyone's with maintain access.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/issues/comments/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List reactions to a comment

```http
GET /api/v3/repos/{owner}/{repo}/issues/comments/{id}/reactions
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `content` | string | no | Only reactions with this content. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/issues/comments/1/reactions" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Add a reaction to a comment

```http
POST /api/v3/repos/{owner}/{repo}/issues/comments/{id}/reactions
```

Needs a signed-in account, and triage access when the conversation is locked. Returns 201 for a new reaction, or 200 with the existing one when you had already reacted with that content.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `content` | string | yes | `+1`, `-1`, `laugh`, `confused`, `heart`, `hooray`, `rocket` or `eyes`. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/issues/comments/1/reactions" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content":"..."}'
```

### Delete a reaction from a comment

```http
DELETE /api/v3/repos/{owner}/{repo}/issues/comments/{id}/reactions/{reaction}
```

Your own reactions, or anyone's with admin access.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |
| `reaction` | string | yes | reaction |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/issues/comments/1/reactions/reaction" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List events in a repository

```http
GET /api/v3/repos/{owner}/{repo}/issues/events
```

Events on every issue and pull request, newest first, each with its `issue`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/issues/events" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get an event

```http
GET /api/v3/repos/{owner}/{repo}/issues/events/{id}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/issues/events/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List labels

```http
GET /api/v3/repos/{owner}/{repo}/labels
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/labels" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a label

```http
POST /api/v3/repos/{owner}/{repo}/labels
```

422 when a label with that name exists; change one with `PATCH /repos/{owner}/{repo}/labels/{name}`.

**Access:** Triage access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | Label name, at most 100 characters. |
| `color` | string | no | 6-digit hex color, with or without `#` (default `ededed`). |
| `description` | string | no | Description. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/labels" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"..."}'
```

### Get a label

```http
GET /api/v3/repos/{owner}/{repo}/labels/{name}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `name` | string | yes | Name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/labels/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update a label

```http
PATCH /api/v3/repos/{owner}/{repo}/labels/{name}
```

Renaming it renames it on every issue too.

**Access:** Triage access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `name` | string | yes | Name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `new_name` | string | no | New name. |
| `color` | string | no | 6-digit hex color, with or without `#`. |
| `description` | string | no | Description. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/repos/acme/website/labels/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a label

```http
DELETE /api/v3/repos/{owner}/{repo}/labels/{name}
```

Also removes it from every issue.

**Access:** Triage access to the repository. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `name` | string | yes | Name. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/labels/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List milestones

```http
GET /api/v3/repos/{owner}/{repo}/milestones
```

Every milestone in the state you ask for (no paging), ordered by due date (milestones without one last), then by number. The `id` is the milestone number. Milestones come from GitHub imports or are created with the endpoint below; the web UI sets an issue's milestone but doesn't create milestones.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | no | `open` (default), `closed` or `all`. Anything else is 422. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/milestones" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a milestone

```http
POST /api/v3/repos/{owner}/{repo}/milestones
```

New milestones are open unless `state` is `closed`. There is no endpoint to delete a milestone.

**Access:** Triage access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | yes | 1 to 255 characters. |
| `description` | string | no | At most 65,536 characters. |
| `state` | string | no | `open` (default) or `closed`. |
| `due_on` | string | no | ISO 8601 timestamp, or `null`. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/milestones" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"..."}'
```

### Get a milestone

```http
GET /api/v3/repos/{owner}/{repo}/milestones/{number}
```

`number` is the milestone number. 404 `milestone not found`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/milestones/42" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update a milestone

```http
PATCH /api/v3/repos/{owner}/{repo}/milestones/{number}
```

Send only the fields you change. Closing records `closed_at`; reopening clears it.

**Access:** Triage access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | no | 1 to 255 characters. |
| `description` | string | no | At most 65,536 characters. |
| `state` | string | no | `open` or `closed`. |
| `due_on` | string | no | ISO 8601 timestamp, or `null` to clear it. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/repos/acme/website/milestones/42" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Pull requests

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/repos/{owner}/{repo}/pulls` | [List pull requests](#list-pull-requests) |
| POST | `/repos/{owner}/{repo}/pulls` | [Open a pull request](#open-a-pull-request) |
| GET | `/repos/{owner}/{repo}/pulls/{number}` | [Get a pull request](#get-a-pull-request) |
| PATCH | `/repos/{owner}/{repo}/pulls/{number}` | [Update a pull request](#update-a-pull-request) |
| PUT | `/repos/{owner}/{repo}/pulls/{number}/auto-merge` | [Enable auto-merge](#enable-auto-merge) |
| DELETE | `/repos/{owner}/{repo}/pulls/{number}/auto-merge` | [Disable auto-merge](#disable-auto-merge) |
| GET | `/repos/{owner}/{repo}/pulls/{number}/comments` | [List review comments](#list-review-comments) |
| POST | `/repos/{owner}/{repo}/pulls/{number}/comments` | [Create a review comment](#create-a-review-comment) |
| POST | `/repos/{owner}/{repo}/pulls/{number}/comments/{id}/replies` | [Reply to a review comment](#reply-to-a-review-comment) |
| GET | `/repos/{owner}/{repo}/pulls/{number}/diffinery/agent-review` | [Get a pull request's agent review](#get-a-pull-requests-agent-review) |
| POST | `/repos/{owner}/{repo}/pulls/{number}/diffinery/agent-review` | [Ask for an agent review](#ask-for-an-agent-review) |
| GET | `/repos/{owner}/{repo}/pulls/{number}/files` | [List changed files](#list-changed-files) |
| GET | `/repos/{owner}/{repo}/pulls/{number}/merge` | [Check mergeability](#check-mergeability) |
| PUT | `/repos/{owner}/{repo}/pulls/{number}/merge` | [Merge a pull request](#merge-a-pull-request) |
| GET | `/repos/{owner}/{repo}/pulls/{number}/requested_reviewers` | [List requested reviewers](#list-requested-reviewers) |
| POST | `/repos/{owner}/{repo}/pulls/{number}/requested_reviewers` | [Request reviewers](#request-reviewers) |
| DELETE | `/repos/{owner}/{repo}/pulls/{number}/requested_reviewers` | [Remove requested reviewers](#remove-requested-reviewers) |
| GET | `/repos/{owner}/{repo}/pulls/{number}/reviews` | [List reviews](#list-reviews) |
| POST | `/repos/{owner}/{repo}/pulls/{number}/reviews` | [Submit a review](#submit-a-review) |
| GET | `/repos/{owner}/{repo}/pulls/{number}/reviews/{id}` | [Get a review](#get-a-review) |
| PUT | `/repos/{owner}/{repo}/pulls/{number}/reviews/{id}/dismissals` | [Dismiss a review](#dismiss-a-review) |
| PUT | `/repos/{owner}/{repo}/pulls/{number}/update-branch` | [Update a pull request's branch](#update-a-pull-requests-branch) |
| GET | `/repos/{owner}/{repo}/pulls/comments` | [List review comments in a repository](#list-review-comments-in-a-repository) |
| GET | `/repos/{owner}/{repo}/pulls/comments/{id}` | [Get a review comment](#get-a-review-comment) |
| PATCH | `/repos/{owner}/{repo}/pulls/comments/{id}` | [Edit a review comment](#edit-a-review-comment) |
| DELETE | `/repos/{owner}/{repo}/pulls/comments/{id}` | [Delete a review comment](#delete-a-review-comment) |
| GET | `/repos/{owner}/{repo}/pulls/comments/{id}/reactions` | [List reactions to a review comment](#list-reactions-to-a-review-comment) |
| POST | `/repos/{owner}/{repo}/pulls/comments/{id}/reactions` | [Add a reaction to a review comment](#add-a-reaction-to-a-review-comment) |
| DELETE | `/repos/{owner}/{repo}/pulls/comments/{id}/reactions/{reaction}` | [Delete a reaction from a review comment](#delete-a-reaction-from-a-review-comment) |

### List pull requests

```http
GET /api/v3/repos/{owner}/{repo}/pulls
```

The total is in the `X-Total-Count` header.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | no | `open` (default), `closed` or `all`. |
| `labels` | string | no | Only pull requests with this label. |
| `creator` | string | no | Only pull requests opened by this login. |
| `q` | string | no | Text search in titles. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/pulls" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Open a pull request

```http
POST /api/v3/repos/{owner}/{repo}/pulls
```

A workflow's `GITHUB_TOKEN` can open one only when the repository allows workflows to create pull requests (`can_approve_pull_request_reviews`, see `PUT /repos/{owner}/{repo}/actions/permissions/workflow`); otherwise 403.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | yes | Title. |
| `head` | string | yes | Branch with the changes (`owner:branch` also works). |
| `base` | string | no | Branch to merge into (default: the default branch). |
| `body` | string | no | Markdown description. |
| `intent` | string | no | Diffinery: what the change is meant to do, shown to reviewers. |
| `draft` | boolean | no | Open as a draft. |
| `reviewers` | string[] | no | Logins to request reviews from. |
| `auto_merge` | boolean | no | Diffinery: `true` turns on auto-merge as it opens, `false` keeps it off where your setting would turn it on. When asked for and it stayed off (for example, the base branch has no required checks), the answer's `auto_merge_skipped` says why. See /docs/collaboration/merge-on-green. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/pulls" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"...","head":"..."}'
```

### Get a pull request

```http
GET /api/v3/repos/{owner}/{repo}/pulls/{number}
```

Includes `mergeable`, `mergeable_state`, `merge_blockers` (why it can't merge yet), `approvals`, `required_approvals` and `checks`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/pulls/42" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update a pull request

```http
PATCH /api/v3/repos/{owner}/{repo}/pulls/{number}
```

The author, or anyone with triage access. `base` isn't supported and is ignored. A merged pull request can't be reopened. A title or body change sends a `pull_request` `edited` event. `draft` is a Diffinery extension (GitHub only offers it through GraphQL): the author or anyone with write access can set it on an open pull request. It records a `ready_for_review` or `convert_to_draft` timeline event and sends the `pull_request` webhook with the action `ready_for_review` or `converted_to_draft`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | no | New title. |
| `body` | string | no | New description. |
| `state` | string | no | `open` or `closed`. |
| `draft` | boolean | no | `false` marks it ready for review; `true` converts it back to a draft. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/repos/acme/website/pulls/42" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Enable auto-merge

```http
PUT /api/v3/repos/{owner}/{repo}/pulls/{number}/auto-merge
```

Diffinery's REST form of GitHub's `enablePullRequestAutoMerge`. Diffinery merges the pull request by itself as soon as every rule of its base branch is met (required checks on the head, approvals from people, linear history), as the caller, never bypassing anything; into a branch with a merge queue it adds it to the queue instead. Returns `{ state, auto_merge, merge_commit_sha }`: `state` is `enabled` (waiting), `queued` or `merged` (it was ready). The pull request's `auto_merge` shows it until then. A push to the head branch by anyone else, or converting the pull request to a draft, turns it off. 422 for a draft, a closed or merged pull request, or one already in the merge queue. Agents and workflow tokens may use it on the default branch or a protected one only when its rule sets `allowAgentAutoMerge` (else 403) and has at least one required check (else 422); a workflow token needs `contents: write`. Audited as `pull_request.auto_merge_enabled`, and the merge as `pull_request.auto_merged`.

**Access:** Write access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `merge_method` | string | no | `merge`, `squash` or `rebase` (default: the queue's method, `squash` where linear history is required, else `merge`). |
| `commit_title` | string | no | Title of the merge or squash commit. |
| `commit_message` | string | no | Body of the merge or squash commit. |
| `delete_branch` | boolean | no | Delete the head branch once auto-merge lands the pull request, directly or through the queue (never the default branch or a protected one). 422 `delete_branch must be a boolean` otherwise. |
| `sha` | string | no | Turn auto-merge on only if the head is still this commit (409 if it moved). |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/pulls/42/auto-merge" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Disable auto-merge

```http
DELETE /api/v3/repos/{owner}/{repo}/pulls/{number}/auto-merge
```

GitHub's `disablePullRequestAutoMerge`. Anyone with write access may turn it off, whoever turned it on; a workflow token needs `contents: write`. 204 even when it was off, which records nothing. Otherwise it records an `auto_merge_disabled` event, sends a `pull_request` webhook with that action, and is audited as `pull_request.auto_merge_disabled`.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/pulls/42/auto-merge" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List review comments

```http
GET /api/v3/repos/{owner}/{repo}/pulls/{number}/comments
```

Line comments from reviews.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/pulls/42/comments" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a review comment

```http
POST /api/v3/repos/{owner}/{repo}/pulls/{number}/comments
```

Adds one line comment as its own `COMMENTED` review, on the current head; `commit_id` is ignored and `position` is read as a line number, not a diff position. Multi-line comments aren't supported. With `in_reply_to`, replies to that comment instead. 422 on a closed pull request.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `body` | string | yes | Markdown body. |
| `path` | string | no | File path (required unless replying). |
| `line` | integer | no | Line number (required unless replying). |
| `side` | string | no | `RIGHT` (default) or `LEFT`. |
| `position` | integer | no | Used as `line` when `line` is missing. |
| `commit_id` | string | no | Accepted and ignored. |
| `in_reply_to` | integer | no | Review comment id to reply to; its path and line are used. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/pulls/42/comments" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"body":"..."}'
```

### Reply to a review comment

```http
POST /api/v3/repos/{owner}/{repo}/pulls/{number}/comments/{id}/replies
```

Adds a reply on the same line, as its own `COMMENTED` review.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `body` | string | yes | Markdown body. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/pulls/42/comments/1/replies" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"body":"..."}'
```

### Get a pull request's agent review

```http
GET /api/v3/repos/{owner}/{repo}/pulls/{number}/diffinery/agent-review
```

The pull request's review task (each review is a run of it), the last reviewed head (`reviewed_sha`) and every finding: `id`, `path`, `line`, `side`, `severity` (`blocking` or `not_blocking`), `title`, `body`, `suggestion`, `state` (`open`, `fixed` or `dismissed`), `fixed_in` and the review `comment_id`. Needs write access.

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/pulls/42/diffinery/agent-review" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Ask for an agent review

```http
POST /api/v3/repos/{owner}/{repo}/pulls/{number}/diffinery/agent-review
```

Reviews the pull request now, or once its current review ends, whatever the trigger setting. People with write access only (any of their tokens); agents can't ask. 422 when agent review is off; 429 past a daily limit (the repository's, or 20 reviews of one pull request in 24 hours). Audited as `review.request`.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `202`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/pulls/42/diffinery/agent-review" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List changed files

```http
GET /api/v3/repos/{owner}/{repo}/pulls/{number}/files
```

Each file with its status, additions, deletions and patch.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/pulls/42/files" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Check mergeability

```http
GET /api/v3/repos/{owner}/{repo}/pulls/{number}/merge
```

Whether the pull request can merge now, and if not, the blockers.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/pulls/42/merge" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Merge a pull request

```http
PUT /api/v3/repos/{owner}/{repo}/pulls/{number}/merge
```

Fails with 405 and the blockers when protection rules aren't met, and with 405 when a merge commit is asked for on a branch that requires linear history (without `merge_method`, such a branch squashes). A branch that requires a merge queue answers 405 too: add the pull request to the queue instead. A repository admin (a person, not an agent or a workflow) can bypass, when the rule doesn't include administrators, there are no conflicts and the pull request isn't a draft. Each flag covers only what it names: `bypass_rules: true` skips unmet rules and linear history, and `bypass_merge_queue: true` skips only the queue. A bypass that skipped an unmet rule, linear history or the queue is audited as `pull_request.merge_bypassed`. Agents can't merge into the default branch or a protected branch themselves (unless the rule sets `agentsMayMerge`); where it sets `allowAgentAutoMerge` they turn on auto-merge (`PUT .../auto-merge`) instead.

**Access:** Write access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `merge_method` | string | no | `merge`, `squash` or `rebase`. |
| `commit_title` | string | no | Title of the merge or squash commit. |
| `commit_message` | string | no | Body of the merge or squash commit. |
| `sha` | string | no | Fail if the head has moved from this commit. |
| `delete_branch` | boolean | no | Delete the head branch after merging. |
| `bypass_merge_queue` | boolean | no | Merge directly even when a queue is required (admins). Doesn't skip unmet rules; send `bypass_rules` too for that. |
| `bypass_rules` | boolean | no | Merge even though protection rules (including linear history) aren't met (admins). Without it, an admin's merge is blocked like anyone else's. |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/pulls/42/merge" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List requested reviewers

```http
GET /api/v3/repos/{owner}/{repo}/pulls/{number}/requested_reviewers
```

Returns `{ users, teams }`; `teams` is always empty.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/pulls/42/requested_reviewers" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Request reviewers

```http
POST /api/v3/repos/{owner}/{repo}/pulls/{number}/requested_reviewers
```

The author, or anyone with triage access. Team reviewers aren't supported: a non-empty `team_reviewers` fails with 422. Sends the `pull_request` webhook (`review_requested`). Returns the pull request.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `reviewers` | string[] | no | Logins. |
| `team_reviewers` | string[] | no | Must be empty or absent. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/pulls/42/requested_reviewers" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Remove requested reviewers

```http
DELETE /api/v3/repos/{owner}/{repo}/pulls/{number}/requested_reviewers
```

The author, or anyone with triage access. Teams aren't supported. Returns the pull request.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `reviewers` | string[] | no | Logins to remove. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/pulls/42/requested_reviewers" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List reviews

```http
GET /api/v3/repos/{owner}/{repo}/pulls/{number}/reviews
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/pulls/42/reviews" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Submit a review

```http
POST /api/v3/repos/{owner}/{repo}/pulls/{number}/reviews
```

Only people's approvals count toward required approvals: agents' and workflows' don't. A workflow's `GITHUB_TOKEN` can approve or request changes only when the repository allows it (`can_approve_pull_request_reviews`); otherwise 403.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `event` | string | no | `APPROVE`, `REQUEST_CHANGES` or `COMMENT` (default). |
| `body` | string | no | Review summary. |
| `comments` | array | no | Line comments: `{ path, line, side: "LEFT" \| "RIGHT", body }`. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/pulls/42/reviews" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a review

```http
GET /api/v3/repos/{owner}/{repo}/pulls/{number}/reviews/{id}
```

`id` is the numeric id or Diffinery's own.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/pulls/42/reviews/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Dismiss a review

```http
PUT /api/v3/repos/{owner}/{repo}/pulls/{number}/reviews/{id}/dismissals
```

Only approvals and change requests can be dismissed. Needs maintain access; agents and the pull request's author can't dismiss. `event` is ignored. Returns the review.

**Access:** Maintain access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `message` | string | yes | Why the review is dismissed. |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/pulls/42/reviews/1/dismissals" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message":"..."}'
```

### Update a pull request's branch

```http
PUT /api/v3/repos/{owner}/{repo}/pulls/{number}/update-branch
```

Merges the base branch into the head branch right away, then answers 202 as GitHub does. 422 when the base has no new commits, on a conflict, or when `expected_head_sha` doesn't match. Branch protection and agent rules apply to the head branch.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `202`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `expected_head_sha` | string | no | Fail unless the head branch is at this commit. |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/pulls/42/update-branch" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List review comments in a repository

```http
GET /api/v3/repos/{owner}/{repo}/pulls/comments
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `since` | string | no | Only comments updated at or after this ISO timestamp. |
| `sort` | string | no | `created` (default) or `updated`. |
| `direction` | string | no | `asc` (default) or `desc`. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/pulls/comments" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a review comment

```http
GET /api/v3/repos/{owner}/{repo}/pulls/comments/{id}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/pulls/comments/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Edit a review comment

```http
PATCH /api/v3/repos/{owner}/{repo}/pulls/comments/{id}
```

Your own comments, or anyone's with maintain access.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `body` | string | yes | New Markdown body. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/repos/acme/website/pulls/comments/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"body":"..."}'
```

### Delete a review comment

```http
DELETE /api/v3/repos/{owner}/{repo}/pulls/comments/{id}
```

Your own comments, or anyone's with maintain access.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/pulls/comments/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List reactions to a review comment

```http
GET /api/v3/repos/{owner}/{repo}/pulls/comments/{id}/reactions
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `content` | string | no | Only reactions with this content. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/pulls/comments/1/reactions" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Add a reaction to a review comment

```http
POST /api/v3/repos/{owner}/{repo}/pulls/comments/{id}/reactions
```

Needs a signed-in account, and triage access when the conversation is locked. Returns 201 for a new reaction, or 200 with the existing one when you had already reacted with that content.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `content` | string | yes | `+1`, `-1`, `laugh`, `confused`, `heart`, `hooray`, `rocket` or `eyes`. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/pulls/comments/1/reactions" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content":"..."}'
```

### Delete a reaction from a review comment

```http
DELETE /api/v3/repos/{owner}/{repo}/pulls/comments/{id}/reactions/{reaction}
```

Your own reactions, or anyone's with admin access.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |
| `reaction` | string | yes | reaction |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/pulls/comments/1/reactions/reaction" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Merge queue

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/repos/{owner}/{repo}/merge-queue/{branch}` | [Get a branch's merge queue](#get-a-branchs-merge-queue) |
| PUT | `/repos/{owner}/{repo}/pulls/{number}/merge-queue` | [Add a pull request to the merge queue](#add-a-pull-request-to-the-merge-queue) |
| DELETE | `/repos/{owner}/{repo}/pulls/{number}/merge-queue` | [Remove a pull request from the merge queue](#remove-a-pull-request-from-the-merge-queue) |

### Get a branch's merge queue

```http
GET /api/v3/repos/{owner}/{repo}/merge-queue/{branch}
```

Diffinery only (GitHub exposes this through GraphQL). Settings and every entry with its merge group and checks.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `branch` | string | yes | Branch name (for protection rules: a branch name or pattern). |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/merge-queue/main" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Add a pull request to the merge queue

```http
PUT /api/v3/repos/{owner}/{repo}/pulls/{number}/merge-queue
```

Diffinery only. Returns 201 with the entry when queued.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `merge_method` | string | no | `merge`, `squash` or `rebase` (default: the queue's method). |
| `delete_branch` | boolean | no | Delete the head branch once merged. |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/pulls/42/merge-queue" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Remove a pull request from the merge queue

```http
DELETE /api/v3/repos/{owner}/{repo}/pulls/{number}/merge-queue
```

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/pulls/42/merge-queue" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Deployments

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/repos/{owner}/{repo}/deployments` | [List deployments](#list-deployments) |
| POST | `/repos/{owner}/{repo}/deployments` | [Create a deployment](#create-a-deployment) |
| GET | `/repos/{owner}/{repo}/deployments/{id}` | [Get a deployment](#get-a-deployment) |
| DELETE | `/repos/{owner}/{repo}/deployments/{id}` | [Delete a deployment](#delete-a-deployment) |
| GET | `/repos/{owner}/{repo}/deployments/{id}/statuses` | [List deployment statuses](#list-deployment-statuses) |
| POST | `/repos/{owner}/{repo}/deployments/{id}/statuses` | [Create a deployment status](#create-a-deployment-status) |

### List deployments

```http
GET /api/v3/repos/{owner}/{repo}/deployments
```

Newest first. Each filter matches exactly.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `sha` | string | no | Full commit SHA. |
| `ref` | string | no | Ref, as given when the deployment was created. |
| `task` | string | no | Task name. |
| `environment` | string | no | Environment name. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/deployments" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a deployment

```http
POST /api/v3/repos/{owner}/{repo}/deployments
```

Unless `required_contexts` is `[]`, every check and status on the commit (or each context you name) must have passed, else 409; checks and statuses reported by agents don't count toward the default set. Creates the environment if needed and sends the `deployment` webhook. Environment names are case-insensitive: an existing environment keeps its spelling, and any spelling of `production` is a production environment. `auto_merge` is ignored. See [Environments](https://diffinery.com/docs/actions/environments).

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `ref` | string | yes | Branch, tag or commit to deploy. |
| `task` | string | no | Task name (default `deploy`). |
| `payload` | object | no | Extra data for the deployer (a string is kept as is). |
| `environment` | string | no | Environment name (default `production`). |
| `description` | string | no | Short description. |
| `transient_environment` | boolean | no | Transient deployments aren't made inactive by later successful ones. |
| `production_environment` | boolean | no | Default: true when the environment is `production`. |
| `required_contexts` | string[] | no | Contexts that must have passed; `[]` skips the check. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/deployments" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ref":"..."}'
```

### Get a deployment

```http
GET /api/v3/repos/{owner}/{repo}/deployments/{id}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/deployments/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a deployment

```http
DELETE /api/v3/repos/{owner}/{repo}/deployments/{id}
```

Refused with 422 while its latest status is `success`, unless it is the only deployment in its environment. Deletes its statuses too.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/deployments/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List deployment statuses

```http
GET /api/v3/repos/{owner}/{repo}/deployments/{id}/statuses
```

Newest first.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/deployments/1/statuses" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a deployment status

```http
POST /api/v3/repos/{owner}/{repo}/deployments/{id}/statuses
```

A `success` status marks older successful deployments to the same environment inactive (except transient and production ones) unless `auto_inactive` is false. A different `environment` moves the deployment there. Sends the `deployment_status` webhook.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | yes | `error`, `failure`, `inactive`, `in_progress`, `queued`, `pending` or `success`. |
| `log_url` | string | no | http(s) link to the deployment's output. |
| `target_url` | string | no | Older name for `log_url`, used when `log_url` is missing. |
| `environment_url` | string | no | http(s) link to the deployed environment. |
| `description` | string | no | Short description (cut at 140 characters). |
| `environment` | string | no | Move the deployment to this environment. |
| `auto_inactive` | boolean | no | `false` keeps older deployments active (default `true`). |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/deployments/1/statuses" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"state":"..."}'
```

## Environments

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/repos/{owner}/{repo}/environments` | [List environments](#list-environments) |
| GET | `/repos/{owner}/{repo}/environments/{env}` | [Get an environment](#get-an-environment) |
| PUT | `/repos/{owner}/{repo}/environments/{env}` | [Create or update an environment](#create-or-update-an-environment) |
| DELETE | `/repos/{owner}/{repo}/environments/{env}` | [Delete an environment](#delete-an-environment) |
| GET | `/repos/{owner}/{repo}/environments/{env}/deployment-branch-policies` | [List deployment branch policies](#list-deployment-branch-policies) |
| POST | `/repos/{owner}/{repo}/environments/{env}/deployment-branch-policies` | [Create a deployment branch policy](#create-a-deployment-branch-policy) |
| DELETE | `/repos/{owner}/{repo}/environments/{env}/deployment-branch-policies/{id}` | [Delete a deployment branch policy](#delete-a-deployment-branch-policy) |
| GET | `/repos/{owner}/{repo}/environments/{env}/secrets` | [List environment secrets](#list-environment-secrets) |
| GET | `/repos/{owner}/{repo}/environments/{env}/secrets/{name}` | [Get an environment secret](#get-an-environment-secret) |
| PUT | `/repos/{owner}/{repo}/environments/{env}/secrets/{name}` | [Set an environment secret](#set-an-environment-secret) |
| DELETE | `/repos/{owner}/{repo}/environments/{env}/secrets/{name}` | [Delete an environment secret](#delete-an-environment-secret) |
| GET | `/repos/{owner}/{repo}/environments/{env}/variables` | [List environment variables](#list-environment-variables) |
| POST | `/repos/{owner}/{repo}/environments/{env}/variables` | [Create an environment variable](#create-an-environment-variable) |
| GET | `/repos/{owner}/{repo}/environments/{env}/variables/{name}` | [Get an environment variable](#get-an-environment-variable) |
| PATCH | `/repos/{owner}/{repo}/environments/{env}/variables/{name}` | [Update an environment variable](#update-an-environment-variable) |
| DELETE | `/repos/{owner}/{repo}/environments/{env}/variables/{name}` | [Delete an environment variable](#delete-an-environment-variable) |

### List environments

```http
GET /api/v3/repos/{owner}/{repo}/environments
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/environments" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get an environment

```http
GET /api/v3/repos/{owner}/{repo}/environments/{env}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `env` | string | yes | env |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/environments/env" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create or update an environment

```http
PUT /api/v3/repos/{owner}/{repo}/environments/{env}
```

People only; agents can't change environments. Required reviewers and a wait timer hold a job that names the environment before anything starts, until a reviewer approves and the timer has passed. Fields left out keep their values. Audited. See [Required reviewers and wait timers](https://diffinery.com/docs/actions/environments#required-reviewers-and-wait-timers).

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `env` | string | yes | env |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `deployment_branch_policy` | object | no | `{ protected_branches, custom_branch_policies }` with exactly one true, or `null` to allow every ref. |
| `wait_timer` | integer | no | Minutes a job waits before it deploys, 0 to 43200. |
| `reviewers` | array | no | Up to 6 people with access, as `{type: "User", id}` (the numeric id the API shows) or `{type: "User", login}`. Never agents; Diffinery has no teams. `[]` or `null` removes them. |
| `prevent_self_review` | boolean | no | Whoever started a run (or an earlier attempt, or owns the agent that did) can't approve it. |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/environments/env" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete an environment

```http
DELETE /api/v3/repos/{owner}/{repo}/environments/{env}
```

Deletes its secrets and variables too. People only. Audited.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `env` | string | yes | env |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/environments/env" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List deployment branch policies

```http
GET /api/v3/repos/{owner}/{repo}/environments/{env}/deployment-branch-policies
```

The branch and tag patterns of an environment with `custom_branch_policies`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `env` | string | yes | env |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/environments/env/deployment-branch-policies" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a deployment branch policy

```http
POST /api/v3/repos/{owner}/{repo}/environments/{env}/deployment-branch-policies
```

The environment must have `custom_branch_policies`. Tag patterns never match tags last pushed by an agent. People only. Audited.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `env` | string | yes | env |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | Branch or tag name pattern, like `release/*`. |
| `type` | string | no | `branch` (default) or `tag`. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/environments/env/deployment-branch-policies" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"..."}'
```

### Delete a deployment branch policy

```http
DELETE /api/v3/repos/{owner}/{repo}/environments/{env}/deployment-branch-policies/{id}
```

People only. Audited.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `env` | string | yes | env |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/environments/env/deployment-branch-policies/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List environment secrets

```http
GET /api/v3/repos/{owner}/{repo}/environments/{env}/secrets
```

Names and dates only; values are never returned.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `env` | string | yes | env |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/environments/env/secrets" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get an environment secret

```http
GET /api/v3/repos/{owner}/{repo}/environments/{env}/secrets/{name}
```

Name and dates only.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `env` | string | yes | env |
| `name` | string | yes | Name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/environments/env/secrets/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Set an environment secret

```http
PUT /api/v3/repos/{owner}/{repo}/environments/{env}/secrets/{name}
```

People only. Names are upper-cased, and `GITHUB_` names are refused. The value is encrypted at rest; GitHub's sealed-box `encrypted_value` isn't supported. The first secret on an environment without a branch policy limits it to protected branches. Returns 201 for a new secret and 204 for a replaced one. Audited.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `env` | string | yes | env |
| `name` | string | yes | Name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | string | yes | Secret value. |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/environments/env/secrets/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"value":"..."}'
```

### Delete an environment secret

```http
DELETE /api/v3/repos/{owner}/{repo}/environments/{env}/secrets/{name}
```

People only. Audited.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `env` | string | yes | env |
| `name` | string | yes | Name. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/environments/env/secrets/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List environment variables

```http
GET /api/v3/repos/{owner}/{repo}/environments/{env}/variables
```

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `env` | string | yes | env |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 10, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/environments/env/variables" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create an environment variable

```http
POST /api/v3/repos/{owner}/{repo}/environments/{env}/variables
```

409 when it exists. Names are upper-cased, and `GITHUB_` names are refused. People only. Audited as `environment.variable.set`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `env` | string | yes | env |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | Variable name. |
| `value` | string | yes | Variable value. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/environments/env/variables" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"...","value":"..."}'
```

### Get an environment variable

```http
GET /api/v3/repos/{owner}/{repo}/environments/{env}/variables/{name}
```

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `env` | string | yes | env |
| `name` | string | yes | Name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/environments/env/variables/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update an environment variable

```http
PATCH /api/v3/repos/{owner}/{repo}/environments/{env}/variables/{name}
```

People only. Renaming onto a name that exists fails with 409. Audited as `environment.variable.set`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `env` | string | yes | env |
| `name` | string | yes | Name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | no | New name (renames the variable). |
| `value` | string | no | New value. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/repos/acme/website/environments/env/variables/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete an environment variable

```http
DELETE /api/v3/repos/{owner}/{repo}/environments/{env}/variables/{name}
```

People only. Audited as `environment.variable.delete`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `env` | string | yes | env |
| `name` | string | yes | Name. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/environments/env/variables/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Actions secrets and variables

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/orgs/{org}/actions/secrets` | [List organization secrets](#list-organization-secrets) |
| GET | `/orgs/{org}/actions/secrets/{name}` | [Get an organization secret](#get-an-organization-secret) |
| PUT | `/orgs/{org}/actions/secrets/{name}` | [Set an organization secret](#set-an-organization-secret) |
| DELETE | `/orgs/{org}/actions/secrets/{name}` | [Delete an organization secret](#delete-an-organization-secret) |
| GET | `/orgs/{org}/actions/secrets/{name}/repositories` | [List a secret's selected repositories](#list-a-secrets-selected-repositories) |
| PUT | `/orgs/{org}/actions/secrets/{name}/repositories` | [Replace a secret's selected repositories](#replace-a-secrets-selected-repositories) |
| PUT | `/orgs/{org}/actions/secrets/{name}/repositories/{repoId}` | [Add a repository to a secret's selection](#add-a-repository-to-a-secrets-selection) |
| DELETE | `/orgs/{org}/actions/secrets/{name}/repositories/{repoId}` | [Remove a repository from a secret's selection](#remove-a-repository-from-a-secrets-selection) |
| GET | `/orgs/{org}/actions/variables` | [List organization variables](#list-organization-variables) |
| POST | `/orgs/{org}/actions/variables` | [Create an organization variable](#create-an-organization-variable) |
| GET | `/orgs/{org}/actions/variables/{name}` | [Get an organization variable](#get-an-organization-variable) |
| PATCH | `/orgs/{org}/actions/variables/{name}` | [Update an organization variable](#update-an-organization-variable) |
| DELETE | `/orgs/{org}/actions/variables/{name}` | [Delete an organization variable](#delete-an-organization-variable) |
| GET | `/repos/{owner}/{repo}/actions/secrets` | [List repository secrets](#list-repository-secrets) |
| PUT | `/repos/{owner}/{repo}/actions/secrets/{name}` | [Set a repository secret](#set-a-repository-secret) |
| DELETE | `/repos/{owner}/{repo}/actions/secrets/{name}` | [Delete a repository secret](#delete-a-repository-secret) |
| GET | `/repos/{owner}/{repo}/actions/variables` | [List repository variables](#list-repository-variables) |
| POST | `/repos/{owner}/{repo}/actions/variables` | [Create a repository variable](#create-a-repository-variable) |
| GET | `/repos/{owner}/{repo}/actions/variables/{name}` | [Get a repository variable](#get-a-repository-variable) |
| PUT | `/repos/{owner}/{repo}/actions/variables/{name}` | [Set a repository variable](#set-a-repository-variable) |
| PATCH | `/repos/{owner}/{repo}/actions/variables/{name}` | [Update a repository variable](#update-a-repository-variable) |
| DELETE | `/repos/{owner}/{repo}/actions/variables/{name}` | [Delete a repository variable](#delete-a-repository-variable) |

### List organization secrets

```http
GET /api/v3/orgs/{org}/actions/secrets
```

Names, update times and `visibility` (`all`, `private` or `selected`), never values.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/actions/secrets" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get an organization secret

```http
GET /api/v3/orgs/{org}/actions/secrets/{name}
```

Its name, update time and `visibility`, never the value. 404 when there is no such secret.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `name` | string | yes | Name. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/actions/secrets/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Set an organization secret

```http
PUT /api/v3/orgs/{org}/actions/secrets/{name}
```

Creates or updates the secret. `visibility` says which of the organization's repositories get it: `all` (the default for a new secret), `private` (private and internal ones) or `selected` (those in `selected_repository_ids`). An update without them keeps the secret's visibility and selection. Names are upper-cased and must match `[A-Z_][A-Z0-9_]*`. People only. Audited as `org.secret.set`. See /docs/actions/secrets-and-variables#organization-secrets.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `name` | string | yes | Name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | string | yes | Secret value. |
| `visibility` | string | no | `all`, `private` or `selected` (422 otherwise). |
| `selected_repository_ids` | integer[] | no | With `selected`: the repositories' numeric ids. An id that isn't one of the organization's repositories gets 422. |

```sh
curl -X PUT "https://diffinery.com/api/v3/orgs/acme/actions/secrets/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"value":"..."}'
```

### Delete an organization secret

```http
DELETE /api/v3/orgs/{org}/actions/secrets/{name}
```

People only. 404 when the organization has no secret with this name. Audited as `org.secret.delete`.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `name` | string | yes | Name. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/orgs/acme/actions/secrets/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List a secret's selected repositories

```http
GET /api/v3/orgs/{org}/actions/secrets/{name}/repositories
```

`{ total_count, repositories }` for a secret with `visibility: selected`; 409 `the secret's visibility isn't selected` otherwise.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `name` | string | yes | Name. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/actions/secrets/website/repositories" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Replace a secret's selected repositories

```http
PUT /api/v3/orgs/{org}/actions/secrets/{name}/repositories
```

Only for a secret with `visibility: selected` (409 otherwise). A repository that leaves the selection stops getting the secret from its next job. Audited as `org.secret.repositories`.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `name` | string | yes | Name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `selected_repository_ids` | integer[] | yes | Every repository that should get the secret. |

```sh
curl -X PUT "https://diffinery.com/api/v3/orgs/acme/actions/secrets/website/repositories" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"selected_repository_ids":"..."}'
```

### Add a repository to a secret's selection

```http
PUT /api/v3/orgs/{org}/actions/secrets/{name}/repositories/{repoId}
```

Only for a secret with `visibility: selected` (409 otherwise). `repoId` is the repository's numeric id. Audited as `org.secret.repository.add`.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `name` | string | yes | Name. |
| `repoId` | string | yes | repoId |

```sh
curl -X PUT "https://diffinery.com/api/v3/orgs/acme/actions/secrets/website/repositories/repoId" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Remove a repository from a secret's selection

```http
DELETE /api/v3/orgs/{org}/actions/secrets/{name}/repositories/{repoId}
```

Only for a secret with `visibility: selected` (409 otherwise). The repository stops getting the secret from its next job. Audited as `org.secret.repository.remove`.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `name` | string | yes | Name. |
| `repoId` | string | yes | repoId |

```sh
curl -X DELETE "https://diffinery.com/api/v3/orgs/acme/actions/secrets/website/repositories/repoId" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List organization variables

```http
GET /api/v3/orgs/{org}/actions/variables
```

Actions variables shared by every repository of the organization: workflows read them as `vars.NAME`, and a repository variable with the same name wins. Returns `total_count` and every variable (no paging) with `name`, `value`, `visibility` (always `all`), `created_at` and `updated_at`. Organization owners and admins who are people (agents get 403 `organization admins only`); anyone outside the organization gets 404.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/actions/variables" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create an organization variable

```http
POST /api/v3/orgs/{org}/actions/variables
```

Creates the variable, or replaces the value of one with that name (GitHub answers 409 instead). Names are stored upper-cased; they must start with a letter or `_`, contain only letters, digits and `_`, and not start with `GITHUB_` (422 `invalid variable name`). Values are strings of at most 49,152 characters (422 `value must be a string of at most 48 KB`). GitHub's `visibility` and `selected_repository_ids` are ignored: every repository of the organization gets the variable. People only. Audited as `org.variable_set`.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | Variable name. |
| `value` | string | yes | Variable value, at most 49,152 characters. |

```sh
curl -X POST "https://diffinery.com/api/v3/orgs/acme/actions/variables" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"...","value":"..."}'
```

### Get an organization variable

```http
GET /api/v3/orgs/{org}/actions/variables/{name}
```

`name` is matched in upper case. 404 `variable not found`. Organization owners and admins who are people.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `name` | string | yes | Name. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/actions/variables/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update an organization variable

```http
PATCH /api/v3/orgs/{org}/actions/variables/{name}
```

Sets the value, creating the variable if it doesn't exist. Renaming isn't supported: a `name` in the body is ignored. Same name and value rules as creating. People only. Audited as `org.variable_set`.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `name` | string | yes | Name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | string | yes | New value, at most 49,152 characters. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/orgs/acme/actions/variables/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"value":"..."}'
```

### Delete an organization variable

```http
DELETE /api/v3/orgs/{org}/actions/variables/{name}
```

404 when the organization has no variable with this name, and nothing is audited. People only. Audited as `org.variable_delete`.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `name` | string | yes | Name. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/orgs/acme/actions/variables/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List repository secrets

```http
GET /api/v3/repos/{owner}/{repo}/actions/secrets
```

Names and update times only; values are never returned.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/secrets" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Set a repository secret

```http
PUT /api/v3/repos/{owner}/{repo}/actions/secrets/{name}
```

People only. The value is encrypted at rest. GitHub's sealed-box `encrypted_value` isn't supported; send `value` over HTTPS. Audited as `repo.secret.set`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `name` | string | yes | Name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | string | yes | Secret value. |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/actions/secrets/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"value":"..."}'
```

### Delete a repository secret

```http
DELETE /api/v3/repos/{owner}/{repo}/actions/secrets/{name}
```

People only. Audited as `repo.secret.delete`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `name` | string | yes | Name. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/actions/secrets/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List repository variables

```http
GET /api/v3/repos/{owner}/{repo}/actions/variables
```

The repository's own variables. Workflows in an organization's repositories also see the organization's variables (`GET /orgs/{org}/actions/variables`), and a repository variable with the same name wins.

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/variables" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a repository variable

```http
POST /api/v3/repos/{owner}/{repo}/actions/variables
```

409 when the repository already has a variable with this name. An organization variable of the same name doesn't count, and the repository's wins in workflows. Names are stored upper-cased. People only. Audited as `repo.variable.set`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | Variable name. |
| `value` | string | yes | Variable value. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/actions/variables" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"...","value":"..."}'
```

### Get a repository variable

```http
GET /api/v3/repos/{owner}/{repo}/actions/variables/{name}
```

404 for a name only the organization has. `created_at` and `updated_at` are always null.

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `name` | string | yes | Name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/variables/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Set a repository variable

```http
PUT /api/v3/repos/{owner}/{repo}/actions/variables/{name}
```

Diffinery's form: creates the variable or replaces its value. GitHub clients use `POST` and `PATCH`. Names are stored upper-cased. People only. Audited as `repo.variable.set`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `name` | string | yes | Name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `value` | string | yes | Variable value. |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/actions/variables/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"value":"..."}'
```

### Update a repository variable

```http
PATCH /api/v3/repos/{owner}/{repo}/actions/variables/{name}
```

404 when the repository has no variable with this name; organization variables aren't changed here. People only. Renaming onto a name that exists fails with 409. Audited as `repo.variable.set`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `name` | string | yes | Name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | no | New name (renames the variable). |
| `value` | string | no | New value. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/repos/acme/website/actions/variables/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a repository variable

```http
DELETE /api/v3/repos/{owner}/{repo}/actions/variables/{name}
```

People only. Names are matched without regard to letter case. Audited as `repo.variable.delete`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `name` | string | yes | Name. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/actions/variables/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Actions artifacts and caches

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/repos/{owner}/{repo}/actions/artifacts` | [List artifacts](#list-artifacts) |
| GET | `/repos/{owner}/{repo}/actions/artifacts/{id}` | [Get an artifact](#get-an-artifact) |
| DELETE | `/repos/{owner}/{repo}/actions/artifacts/{id}` | [Delete an artifact](#delete-an-artifact) |
| GET | `/repos/{owner}/{repo}/actions/artifacts/{id}/{format}` | [Download an artifact](#download-an-artifact) |
| GET | `/repos/{owner}/{repo}/actions/cache/usage` | [Get cache usage](#get-cache-usage) |
| GET | `/repos/{owner}/{repo}/actions/caches` | [List caches](#list-caches) |
| DELETE | `/repos/{owner}/{repo}/actions/caches` | [Delete caches by key](#delete-caches-by-key) |
| DELETE | `/repos/{owner}/{repo}/actions/caches/{id}` | [Delete a cache](#delete-a-cache) |
| GET | `/repos/{owner}/{repo}/actions/runs/{runId}/artifacts` | [List a run's artifacts](#list-a-runs-artifacts) |

### List artifacts

```http
GET /api/v3/repos/{owner}/{repo}/actions/artifacts
```

Every artifact in the repository, newest first. Each has a numeric `id`, `name`, `size_in_bytes`, `digest` (`sha256:...` when the uploader sent one), `created_at`, `expires_at`, `expired`, an `archive_download_url`, and `workflow_run` (its `id` is the run number). An artifact past its retention stays listed with `expired: true` for 90 more days; its content is already deleted. Returns `{ total_count, artifacts }`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | no | Only artifacts with exactly this name. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/artifacts" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get an artifact

```http
GET /api/v3/repos/{owner}/{repo}/actions/artifacts/{id}
```

`id` is the artifact's numeric id. Expired artifacts are returned too, with `expired: true`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/artifacts/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete an artifact

```http
DELETE /api/v3/repos/{owner}/{repo}/actions/artifacts/{id}
```

Deletes the artifact and its content, expired or not; it no longer counts toward the repository's artifact quota. 404 when there is no artifact with that id. Audited as `actions.artifact.delete`.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/actions/artifacts/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Download an artifact

```http
GET /api/v3/repos/{owner}/{repo}/actions/artifacts/{id}/{format}
```

`format` must be `zip` (anything else is 404). Redirects with 302 to a signed URL that works for 10 minutes and needs no token; follow redirects (`curl -L`). The content is a zip, or the file itself for an artifact uploaded as a single unzipped file. 410 `Artifact has expired` once the artifact has expired.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope. **Success:** `302`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |
| `format` | string | yes | Archive format: `zip`. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/artifacts/1/zip" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get cache usage

```http
GET /api/v3/repos/{owner}/{repo}/actions/cache/usage
```

`full_name`, `active_caches_size_in_bytes` and `active_caches_count` of the saved entries. A repository keeps up to 10 GB of caches; see [Limits](https://diffinery.com/docs/reference/limits#caches-and-artifacts).

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/cache/usage" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List caches

```http
GET /api/v3/repos/{owner}/{repo}/actions/caches
```

Saved cache entries; uploads in progress aren't listed. Each has a numeric `id`, `key`, `version`, `ref` (the ref it was saved for, like `refs/heads/main`), `size_in_bytes`, `created_at` and `last_accessed_at`. Returns `{ total_count, actions_caches }`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `key` | string | no | Only entries whose key starts with this. |
| `ref` | string | no | Only entries saved for this full ref, like `refs/heads/main`. |
| `sort` | string | no | `last_accessed_at` (default), `created_at` or `size_in_bytes`. |
| `direction` | string | no | `desc` (default) or `asc`. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/caches" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete caches by key

```http
DELETE /api/v3/repos/{owner}/{repo}/actions/caches
```

Deletes every entry whose key is exactly `key` (all versions), or only those saved for `ref`. Returns the deleted entries as `{ total_count, actions_caches }`. 422 `key is required` without `key`, 404 when nothing matched. Audited as `actions.cache.delete`.

**Access:** Write access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `key` | string | yes | The exact cache key. |
| `ref` | string | no | Only entries saved for this full ref, like `refs/heads/main`. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/actions/caches" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a cache

```http
DELETE /api/v3/repos/{owner}/{repo}/actions/caches/{id}
```

By the entry's numeric id. 404 when there is none. Audited as `actions.cache.delete`.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/actions/caches/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List a run's artifacts

```http
GET /api/v3/repos/{owner}/{repo}/actions/runs/{runId}/artifacts
```

Newest first, in the same shape as `GET /repos/{owner}/{repo}/actions/artifacts`. `runId` is the run's id, or its number (`github.run_id` in workflows), which covers every attempt of the run. Expired artifacts are listed with `expired: true`; their content is gone.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `runId` | string | yes | Workflow run id, or the run number (`github.run_id`). |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | no | Only artifacts with exactly this name. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/runs/42/artifacts" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Actions

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/repos/{owner}/{repo}/actions/jobs/{id}` | [Get a job](#get-a-job) |
| GET | `/repos/{owner}/{repo}/actions/jobs/{id}/logs` | [Get a job's logs](#get-a-jobs-logs) |
| POST | `/repos/{owner}/{repo}/actions/jobs/{id}/rerun` | [Re-run a job](#re-run-a-job) |
| GET | `/repos/{owner}/{repo}/actions/permissions/workflow` | [Get workflow token permissions](#get-workflow-token-permissions) |
| PUT | `/repos/{owner}/{repo}/actions/permissions/workflow` | [Set workflow token permissions](#set-workflow-token-permissions) |
| GET | `/repos/{owner}/{repo}/actions/runners` | [List self-hosted runners](#list-self-hosted-runners) |
| DELETE | `/repos/{owner}/{repo}/actions/runners/{id}` | [Remove a self-hosted runner](#remove-a-self-hosted-runner) |
| POST | `/repos/{owner}/{repo}/actions/runners/claim` | [Claim a job for a self-hosted runner](#claim-a-job-for-a-self-hosted-runner) |
| POST | `/repos/{owner}/{repo}/actions/runners/register` | [Register a self-hosted runner](#register-a-self-hosted-runner) |
| POST | `/repos/{owner}/{repo}/actions/runners/registration-token` | [Create a runner registration token](#create-a-runner-registration-token) |
| GET | `/repos/{owner}/{repo}/actions/runs` | [List workflow runs](#list-workflow-runs) |
| GET | `/repos/{owner}/{repo}/actions/runs/{id}` | [Get a workflow run](#get-a-workflow-run) |
| GET | `/repos/{owner}/{repo}/actions/runs/{id}/approvals` | [List a run's deployment reviews](#list-a-runs-deployment-reviews) |
| GET | `/repos/{owner}/{repo}/actions/runs/{id}/attempts/{attempt}` | [Get a run attempt](#get-a-run-attempt) |
| POST | `/repos/{owner}/{repo}/actions/runs/{id}/cancel` | [Cancel a run](#cancel-a-run) |
| GET | `/repos/{owner}/{repo}/actions/runs/{id}/jobs` | [List a run's jobs](#list-a-runs-jobs) |
| GET | `/repos/{owner}/{repo}/actions/runs/{id}/logs` | [Download a run's logs](#download-a-runs-logs) |
| DELETE | `/repos/{owner}/{repo}/actions/runs/{id}/logs` | [Delete a run's logs](#delete-a-runs-logs) |
| GET | `/repos/{owner}/{repo}/actions/runs/{id}/pending_deployments` | [List the environments a run waits on](#list-the-environments-a-run-waits-on) |
| POST | `/repos/{owner}/{repo}/actions/runs/{id}/pending_deployments` | [Approve or reject a run's pending deployments](#approve-or-reject-a-runs-pending-deployments) |
| POST | `/repos/{owner}/{repo}/actions/runs/{id}/rerun` | [Re-run a workflow run](#re-run-a-workflow-run) |
| POST | `/repos/{owner}/{repo}/actions/runs/{id}/rerun-failed-jobs` | [Re-run a run's failed jobs](#re-run-a-runs-failed-jobs) |
| GET | `/repos/{owner}/{repo}/actions/workflows` | [List workflows](#list-workflows) |
| GET | `/repos/{owner}/{repo}/actions/workflows/{workflow}` | [Get a workflow](#get-a-workflow) |
| POST | `/repos/{owner}/{repo}/actions/workflows/{workflow}/dispatches` | [Run a workflow (workflow_dispatch)](#run-a-workflow-workflow_dispatch) |
| GET | `/repos/{owner}/{repo}/actions/workflows/{workflow}/runs` | [List a workflow's runs](#list-a-workflows-runs) |

### Get a job

```http
GET /api/v3/repos/{owner}/{repo}/actions/jobs/{id}
```

The job with its steps. GitHub's job fields, plus Diffinery's own: `runner` (the hosted container's `image`, `location` and `instance`; `null` on a self-hosted runner) and `placementTries` (how many times a hosted job went back in line before a runner took it: no free container, or a runner on a replaced image) and `restarts` (how many times it started over because the platform replaced its runner before its steps ran). See /docs/actions/runners.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/jobs/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a job's logs

```http
GET /api/v3/repos/{owner}/{repo}/actions/jobs/{id}/logs
```

Plain text, one timestamped line each, or JSON with `format=json`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `format` | string | no | `json` for an array of `{ t, text }` lines. |
| `after` | integer | no | Only lines after this sequence number (for following a live log). |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/jobs/1/logs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Re-run a job

```http
POST /api/v3/repos/{owner}/{repo}/actions/jobs/{id}/rerun
```

Starts a new attempt of the job's run that runs this job (this matrix leg) and every job that depends on it; the other jobs are kept from the earlier attempt as they were. Answers `{ run_id }`, the new attempt's id. 409 when the run hasn't finished. A workflow's `GITHUB_TOKEN` can't re-run workflows (403).

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `enable_debug_logging` | boolean | no | Accepted and ignored. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/actions/jobs/1/rerun" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get workflow token permissions

```http
GET /api/v3/repos/{owner}/{repo}/actions/permissions/workflow
```

The defaults for the `GITHUB_TOKEN` of the repository's workflows (GitHub's "Workflow permissions" setting). `default_workflow_permissions` is what a job without `permissions:` gets: `read` (contents and packages read, nothing else) or `write` (read and write on every scope except `id-token`). `can_approve_pull_request_reviews` says whether job tokens may open pull requests and approve or request changes. `agent_runs_use_secrets` (a Diffinery addition, `false` by default) says whether runs of code an agent wrote get the repository's and organization's secrets. New repositories start with `read` and `false`; repositories created before the setting existed have `write` and `false`. See [Workflow permissions](https://diffinery.com/docs/actions/workflow-permissions).

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/permissions/workflow" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Set workflow token permissions

```http
PUT /api/v3/repos/{owner}/{repo}/actions/permissions/workflow
```

Send only what changes. People only: agents get 403 `only people can change what workflows are allowed to do`. Applies to jobs that start afterwards. Each change is audited as `repo.actions_workflow_settings`. Even when allowed, a workflow's approval never counts toward required approvals.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `default_workflow_permissions` | string | no | `read` or `write`. |
| `can_approve_pull_request_reviews` | boolean | no | Allow workflows' `GITHUB_TOKEN` to open pull requests and to approve or request changes. |
| `agent_runs_use_secrets` | boolean | no | Give runs of code an agent wrote (an agent triggered the run, pushed its branch last, or opened or pushed to its pull request) the repository's and organization's secrets. Default `false`. |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/actions/permissions/workflow" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List self-hosted runners

```http
GET /api/v3/repos/{owner}/{repo}/actions/runners
```

GitHub's shape: `{ total_count, runners }`, each with `id`, `name`, `os`, `status` (`online` when it polled in the last 90 seconds, otherwise `offline`), `busy`, `ephemeral` and `labels`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/runners" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Remove a self-hosted runner

```http
DELETE /api/v3/repos/{owner}/{repo}/actions/runners/{id}
```

Its runner token stops working at once. A job it is running carries on with its own job token. Audited as `runner.remove`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/actions/runners/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Claim a job for a self-hosted runner

```http
POST /api/v3/repos/{owner}/{repo}/actions/runners/claim
```

Used by `diffinery runner`. Send the runner's `drn_` token and an empty body: the runner offers the name and labels it registered with. Only registered runners claim: a personal token, even a repository admin's, gets 403 `personal tokens can't claim jobs; register this runner: ...`. Returns 204 when no queued job matches the labels, otherwise the job with a fresh job token. See /docs/actions/runners.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/actions/runners/claim" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Register a self-hosted runner

```http
POST /api/v3/repos/{owner}/{repo}/actions/runners/register
```

Trades a registration token for the runner's own `drn_` token, shown once, which can claim this repository's jobs and nothing else. No `Authorization` header: the registration token is the credential. A wrong or expired token, or a repository that doesn't exist, gets 401 `invalid or expired registration token`. At most 100 runners per repository and 20 labels per runner (429 past the runner limit). Returns `{ id, name, labels, ephemeral, token }`. Audited as `runner.register`, with the admin who created the registration token as the actor.

**Access:** No authentication needed. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `registration_token` | string | yes | A `drg_` token from `POST .../actions/runners/registration-token`. |
| `name` | string | no | Runner name (default `runner`). |
| `labels` | string[] | no | Labels the runner offers, matched against `runs-on`. |
| `ephemeral` | boolean | no | `true` for a single job: the runner's token stops working once it takes a job, and the runner is removed when the job finishes. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/actions/runners/register" \
  -H "Content-Type: application/json" \
  -d '{"registration_token":"..."}'
```

### Create a runner registration token

```http
POST /api/v3/repos/{owner}/{repo}/actions/runners/registration-token
```

As on GitHub: a `drg_` token that registers any number of self-hosted runners with this repository for an hour. Returns `{ token, expires_at }`. People only: agents, job tokens and sandbox tokens get 403 `only repository admins can add self-hosted runners`. Audited as `runner.registration_token`. See /docs/actions/runners#manage-runners.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/actions/runners/registration-token" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List workflow runs

```http
GET /api/v3/repos/{owner}/{repo}/actions/runs
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `workflow` | string | no | Workflow file path. |
| `branch` | string | no | Head branch. |
| `status` | string | no | Run status or conclusion. |
| `event` | string | no | Triggering event. |
| `head_sha` | string | no | Head commit. |
| `per_page` | integer | no | Results per page (default 25, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/runs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a workflow run

```http
GET /api/v3/repos/{owner}/{repo}/actions/runs/{id}
```

The run with its jobs. `id` is the run's id, or its number (`github.run_id` in workflows), which picks the latest attempt.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/runs/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List a run's deployment reviews

```http
GET /api/v3/repos/{owner}/{repo}/actions/runs/{id}/approvals
```

Each reviewer's decision, with the environment and comment.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/runs/1/approvals" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a run attempt

```http
GET /api/v3/repos/{owner}/{repo}/actions/runs/{id}/attempts/{attempt}
```

Re-runs are stored as separate runs with the same run number; this returns attempt `attempt` of the run's number.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |
| `attempt` | string | yes | attempt |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/runs/1/attempts/attempt" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Cancel a run

```http
POST /api/v3/repos/{owner}/{repo}/actions/runs/{id}/cancel
```

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `202`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/actions/runs/1/cancel" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List a run's jobs

```http
GET /api/v3/repos/{owner}/{repo}/actions/runs/{id}/jobs
```

Each job as `GET .../actions/jobs/{id}` returns it, with `runner`, `placementTries` and `restarts`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/runs/1/jobs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Download a run's logs

```http
GET /api/v3/repos/{owner}/{repo}/actions/runs/{id}/logs
```

A zip with one text file per job. Jobs past 24 MB of logs in total are left out.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/runs/1/logs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a run's logs

```http
DELETE /api/v3/repos/{owner}/{repo}/actions/runs/{id}/logs
```

Deletes every job's log and step summary for good; the run, its jobs, checks and artifacts stay. Only for a finished run (409 otherwise). An agent can delete only the logs of runs that didn't run on the default branch or a protected branch, and a workflow's `GITHUB_TOKEN` can't delete logs (403). Audited as `repo.actions.logs.delete`.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/actions/runs/1/logs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List the environments a run waits on

```http
GET /api/v3/repos/{owner}/{repo}/actions/runs/{id}/pending_deployments
```

Environments whose required reviewers or wait timer hold the run's jobs, with `current_user_can_approve` for the caller. See [Required reviewers and wait timers](https://diffinery.com/docs/actions/environments#required-reviewers-and-wait-timers).

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/runs/1/pending_deployments" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Approve or reject a run's pending deployments

```http
POST /api/v3/repos/{owner}/{repo}/actions/runs/{id}/pending_deployments
```

Only a listed reviewer, signed in or with a `write` token: never an agent, a workflow's token or a sandbox token (403). With `prevent_self_review`, not whoever started the run (403). One decision per environment and run counts; 422 when nothing waits. Approved jobs start once their wait timer has passed; rejected ones fail. Returns the deployments of the jobs that were waiting. Audited as `deployment.approve` or `deployment.reject`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `environment_ids` | array | yes | Ids of the environments to decide. |
| `state` | string | yes | `approved` or `rejected`. |
| `comment` | string | no | Shown with the decision and in the audit log. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/actions/runs/1/pending_deployments" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"environment_ids":[],"state":"..."}'
```

### Re-run a workflow run

```http
POST /api/v3/repos/{owner}/{repo}/actions/runs/{id}/rerun
```

Starts a new attempt that runs every job again. Answers `{ run_id }`, the new attempt's id. A workflow's `GITHUB_TOKEN` can't re-run workflows (403).

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `enable_debug_logging` | boolean | no | Accepted and ignored. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/actions/runs/1/rerun" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Re-run a run's failed jobs

```http
POST /api/v3/repos/{owner}/{repo}/actions/runs/{id}/rerun-failed-jobs
```

Starts a new attempt that runs the jobs and matrix legs that failed, were cancelled or timed out, and every job that depends on them. The others are kept from the earlier attempt as they were, with their logs and artifacts. Answers `{ run_id }`, the new attempt's id. 409 `this run has no failed jobs to re-run`, or when the run hasn't finished. A workflow's `GITHUB_TOKEN` can't re-run workflows (403).

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `enable_debug_logging` | boolean | no | Accepted and ignored. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/actions/runs/1/rerun-failed-jobs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List workflows

```http
GET /api/v3/repos/{owner}/{repo}/actions/workflows
```

Each workflow file with its triggers, and parse errors for invalid ones (`state: invalid`).

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/workflows" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a workflow

```http
GET /api/v3/repos/{owner}/{repo}/actions/workflows/{workflow}
```

`workflow` is the file path or file name; the response's `id` is the path. `created_at` and `updated_at` are the time of the request, not of the file.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `workflow` | string | yes | Workflow file path (URL-encoded) or file name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/workflows/ci.yml" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Run a workflow (workflow_dispatch)

```http
POST /api/v3/repos/{owner}/{repo}/actions/workflows/{workflow}/dispatches
```

`workflow` is the file path or name, URL-encoded, like `.github%2Fworkflows%2Fdeploy.yml` or `deploy.yml`. Returns the new run's id. Fails with 429 when the repository already has 500 unfinished workflow runs.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `workflow` | string | yes | Workflow file path (URL-encoded) or file name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `ref` | string | yes | Branch or tag to run on. |
| `inputs` | object | no | Values for `on.workflow_dispatch.inputs`. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/actions/workflows/ci.yml/dispatches" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ref":"..."}'
```

### List a workflow's runs

```http
GET /api/v3/repos/{owner}/{repo}/actions/workflows/{workflow}/runs
```

No `Link` header; page with `total_count`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `workflow` | string | yes | Workflow file path (URL-encoded) or file name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `branch` | string | no | Head branch. |
| `status` | string | no | Run status or conclusion. |
| `event` | string | no | Triggering event. |
| `head_sha` | string | no | Head commit. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/actions/workflows/ci.yml/runs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Webhooks

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/repos/{owner}/{repo}/hooks` | [List webhooks](#list-webhooks) |
| POST | `/repos/{owner}/{repo}/hooks` | [Create a webhook](#create-a-webhook) |
| DELETE | `/repos/{owner}/{repo}/hooks/{id}` | [Delete a webhook](#delete-a-webhook) |

### List webhooks

```http
GET /api/v3/repos/{owner}/{repo}/hooks
```

Secrets are never returned.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/hooks" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a webhook

```http
POST /api/v3/repos/{owner}/{repo}/hooks
```

`config.url` must be `https://` to a public host: `localhost`, single-label, `.local` and `.internal` names, private, loopback and link-local addresses get 422 `webhook URL must be a public host`, and Diffinery's own host 422 `webhook URL can't point at Diffinery itself`. At most 20 webhooks per repository (422). Audited as `repo.webhook.create`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `config` | object | yes | `{ url, secret }`. The secret signs each delivery (`X-Hub-Signature-256`). |
| `events` | string[] | no | Event names, or `["*"]` (default) for all. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/hooks" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"config":{}}'
```

### Delete a webhook

```http
DELETE /api/v3/repos/{owner}/{repo}/hooks/{id}
```

Audited as `repo.webhook.delete`.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/hooks/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Packages

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/orgs/{owner}/packages` | [List an organization's packages](#list-an-organizations-packages) |
| GET | `/orgs/{owner}/packages/{type}/{name}` | [Get one of an organization's packages](#get-one-of-an-organizations-packages) |
| PATCH | `/orgs/{owner}/packages/{type}/{name}` | [Update one of an organization's packages](#update-one-of-an-organizations-packages) |
| DELETE | `/orgs/{owner}/packages/{type}/{name}` | [Delete one of an organization's packages](#delete-one-of-an-organizations-packages) |
| GET | `/orgs/{owner}/packages/{type}/{name}/versions` | [List package versions](#list-package-versions) |
| GET | `/orgs/{owner}/packages/{type}/{name}/versions/{id}` | [Get a package version](#get-a-package-version) |
| DELETE | `/orgs/{owner}/packages/{type}/{name}/versions/{id}` | [Delete a package version](#delete-a-package-version) |
| GET | `/repos/{owner}/{repo}/packages` | [List a repository's packages](#list-a-repositorys-packages) |
| GET | `/user/packages` | [List your packages](#list-your-packages) |
| GET | `/user/packages/{type}/{name}` | [Get one of your packages](#get-one-of-your-packages) |
| PATCH | `/user/packages/{type}/{name}` | [Update one of your packages](#update-one-of-your-packages) |
| DELETE | `/user/packages/{type}/{name}` | [Delete one of your packages](#delete-one-of-your-packages) |
| GET | `/user/packages/{type}/{name}/versions` | [List package versions](#list-package-versions-get-userpackagestypenameversions) |
| GET | `/user/packages/{type}/{name}/versions/{id}` | [Get a package version](#get-a-package-version-get-userpackagestypenameversionsid) |
| DELETE | `/user/packages/{type}/{name}/versions/{id}` | [Delete a package version](#delete-a-package-version-delete-userpackagestypenameversionsid) |
| GET | `/users/{owner}/packages` | [List a user's packages](#list-a-users-packages) |
| GET | `/users/{owner}/packages/{type}/{name}` | [Get one of a user's packages](#get-one-of-a-users-packages) |
| PATCH | `/users/{owner}/packages/{type}/{name}` | [Update one of a user's packages](#update-one-of-a-users-packages) |
| DELETE | `/users/{owner}/packages/{type}/{name}` | [Delete one of a user's packages](#delete-one-of-a-users-packages) |
| GET | `/users/{owner}/packages/{type}/{name}/versions` | [List package versions](#list-package-versions-get-usersownerpackagestypenameversions) |
| GET | `/users/{owner}/packages/{type}/{name}/versions/{id}` | [Get a package version](#get-a-package-version-get-usersownerpackagestypenameversionsid) |
| DELETE | `/users/{owner}/packages/{type}/{name}/versions/{id}` | [Delete a package version](#delete-a-package-version-delete-usersownerpackagestypenameversionsid) |

### List an organization's packages

```http
GET /api/v3/orgs/{owner}/packages
```

Only packages you can pull.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/packages" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get one of an organization's packages

```http
GET /api/v3/orgs/{owner}/packages/{type}/{name}
```

`type` is `container`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/packages/container/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update one of an organization's packages

```http
PATCH /api/v3/orgs/{owner}/packages/{type}/{name}
```

Change its visibility or the repository it is linked to.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `visibility` | string | no | `private` or `public`. |
| `repository` | string | no | Repository name to link, or `null` to unlink. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/orgs/acme/packages/container/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete one of an organization's packages

```http
DELETE /api/v3/orgs/{owner}/packages/{type}/{name}
```

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/orgs/acme/packages/container/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List package versions

```http
GET /api/v3/orgs/{owner}/packages/{type}/{name}/versions
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | no | `tagged` for tagged versions only. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/packages/container/website/versions" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a package version

```http
GET /api/v3/orgs/{owner}/packages/{type}/{name}/versions/{id}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/packages/container/website/versions/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a package version

```http
DELETE /api/v3/orgs/{owner}/packages/{type}/{name}/versions/{id}
```

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/orgs/acme/packages/container/website/versions/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List a repository's packages

```http
GET /api/v3/repos/{owner}/{repo}/packages
```

Container images linked to the repository.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/packages" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List your packages

```http
GET /api/v3/user/packages
```

Only packages you can pull.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/user/packages" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get one of your packages

```http
GET /api/v3/user/packages/{type}/{name}
```

`type` is `container`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |

```sh
curl "https://diffinery.com/api/v3/user/packages/container/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update one of your packages

```http
PATCH /api/v3/user/packages/{type}/{name}
```

Change its visibility or the repository it is linked to.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `visibility` | string | no | `private` or `public`. |
| `repository` | string | no | Repository name to link, or `null` to unlink. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/user/packages/container/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete one of your packages

```http
DELETE /api/v3/user/packages/{type}/{name}
```

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/user/packages/container/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List package versions (GET /user/packages/type/name/versions)

```http
GET /api/v3/user/packages/{type}/{name}/versions
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | no | `tagged` for tagged versions only. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/user/packages/container/website/versions" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a package version (GET /user/packages/type/name/versions/id)

```http
GET /api/v3/user/packages/{type}/{name}/versions/{id}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/user/packages/container/website/versions/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a package version (DELETE /user/packages/type/name/versions/id)

```http
DELETE /api/v3/user/packages/{type}/{name}/versions/{id}
```

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/user/packages/container/website/versions/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List a user's packages

```http
GET /api/v3/users/{owner}/packages
```

Only packages you can pull.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |

```sh
curl "https://diffinery.com/api/v3/users/acme/packages" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get one of a user's packages

```http
GET /api/v3/users/{owner}/packages/{type}/{name}
```

`type` is `container`.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |

```sh
curl "https://diffinery.com/api/v3/users/acme/packages/container/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update one of a user's packages

```http
PATCH /api/v3/users/{owner}/packages/{type}/{name}
```

Change its visibility or the repository it is linked to.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `visibility` | string | no | `private` or `public`. |
| `repository` | string | no | Repository name to link, or `null` to unlink. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/users/acme/packages/container/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete one of a user's packages

```http
DELETE /api/v3/users/{owner}/packages/{type}/{name}
```

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/users/acme/packages/container/website" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List package versions (GET /users/owner/packages/type/name/versions)

```http
GET /api/v3/users/{owner}/packages/{type}/{name}/versions
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | no | `tagged` for tagged versions only. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/users/acme/packages/container/website/versions" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a package version (GET /users/owner/packages/type/name/versions/id)

```http
GET /api/v3/users/{owner}/packages/{type}/{name}/versions/{id}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/users/acme/packages/container/website/versions/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a package version (DELETE /users/owner/packages/type/name/versions/id)

```http
DELETE /api/v3/users/{owner}/packages/{type}/{name}/versions/{id}
```

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `type` | string | yes | Package type: `container`. |
| `name` | string | yes | Name. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/users/acme/packages/container/website/versions/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Imports

| Method | Path | Summary |
| --- | --- | --- |
| DELETE | `/diffinery/admin/linked-accounts/{id}` | [Clear anyone's GitHub link](#clear-anyones-github-link) |
| GET | `/diffinery/imports` | [List your imports](#list-your-imports) |
| POST | `/diffinery/imports` | [Start a GitHub import](#start-a-github-import) |
| GET | `/diffinery/imports/{id}` | [Get an import](#get-an-import) |
| POST | `/diffinery/imports/{id}/agent/complete` | [Report a Git transfer's result (import agent)](#report-a-git-transfers-result-import-agent) |
| POST | `/diffinery/imports/{id}/agent/progress` | [Report Git transfer progress (import agent)](#report-git-transfer-progress-import-agent) |
| GET | `/diffinery/imports/{id}/agent/spec` | [Get a Git transfer spec (import agent)](#get-a-git-transfer-spec-import-agent) |
| POST | `/diffinery/imports/{id}/cancel` | [Cancel an import](#cancel-an-import) |
| POST | `/diffinery/imports/{id}/claim` | [Claim an import's Git transfer (local development)](#claim-an-imports-git-transfer-local-development) |
| POST | `/diffinery/imports/{id}/retry` | [Retry an import](#retry-an-import) |
| POST | `/diffinery/imports/{id}/selection` | [Choose repositories for a draft import](#choose-repositories-for-a-draft-import) |
| GET | `/diffinery/user/linked-accounts` | [List your linked GitHub accounts](#list-your-linked-github-accounts) |
| DELETE | `/diffinery/user/linked-accounts/{id}` | [Unlink a GitHub account](#unlink-a-github-account) |
| POST | `/diffinery/user/linked-accounts/github` | [Link a GitHub account](#link-a-github-account) |
| POST | `/diffinery/user/linked-accounts/github/challenge` | [Get a GitHub link code](#get-a-github-link-code) |

### Clear anyone's GitHub link

```http
DELETE /api/v3/diffinery/admin/linked-accounts/{id}
```

For example after an account changes hands. `id` is the link id from `GET /diffinery/user/linked-accounts` of the account that owns it; there is no endpoint that lists other people's links. 404 `link not found`, 403 `site admin only`. Audited as `account.link_cleared`.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/diffinery/admin/linked-accounts/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List your imports

```http
GET /api/v3/diffinery/imports
```

The imports you started, newest first, at most 100. Repository imports that belong to an organization import aren't listed separately; read them through the organization import's `children`.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/diffinery/imports" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Start a GitHub import

```http
POST /api/v3/diffinery/imports
```

Imports one GitHub repository (`source`), or many repositories of a GitHub organization or user (`source_owner`), on the server, and returns the import (`status: queued`). Git history with LFS objects is copied in a container; issues and pull requests (with their numbers), comments, reviews, labels, milestones, branch protection, Actions variables, deployment environments and releases come through GitHub's REST API. Secret values are never read: only secret names are listed in `summary`, for a person to set by hand. People can import into their own account or an organization they own or administer (site administrators: any user or organization). An agent can import only where its owner may (the owner's own account or an organization the owner owns or administers; an organization's agent, only into that organization), and only when its policy allows `write`; its imports always use `secrets: stop` and skip Actions variables and environments. Needs a `write` or `admin` token (403 `starting an import needs a token with write or admin scope`), or a browser session. At most one organization import and three repository imports run at a time per account and per target (429), and a `source` repository larger than `IMPORT_MAX_REPO_KB` (default 10 GB, by GitHub's reported size) is refused with 422. Other errors: 422 `<owner>/<name> already exists; choose another name`, 422 `GitHub repository <source> was not found or the token cannot read it`, 422 `GitHub rejected the token (expired or revoked?)`, 429 when GitHub's rate limit is reached, 502 `could not reach GitHub: ...`. Audited as `import.create`. See [Migrate from GitHub](https://diffinery.com/docs/migrate-from-github).

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope. **Success:** `201`.

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `source` | string | no | One repository: `owner/name`, a github.com or GitHub Enterprise URL, or an SSH remote such as `git@github.com:owner/name.git`. Send either `source` or `source_owner`. |
| `source_owner` | string | no | A GitHub organization or user: imports its repositories (private ones too when the token can see them). |
| `owner` | string | yes | The Diffinery user or organization that will own the new repositories. |
| `name` | string | no | `source` only: the new repository's name. Default: the GitHub name. It must not exist yet. |
| `visibility` | string | no | `keep` (default: public stays public, private and internal become private), `private` or `public`. `internal` is accepted and means `private`. |
| `github_token` | string | no | A GitHub token that can read the source, at most 400 characters. Needed for private repositories; Actions variables, secret names and branch protection need a token with admin access to the source. Encrypted at rest, used only by this import, deleted when it ends, never returned. |
| `github_api_url` | string | no | GitHub Enterprise Server: the REST API base, such as `https://ghe.example.com/api/v3` (default `https://api.github.com`). Must be HTTPS on a public host. Required, on the same host as `source`, when `source` names an Enterprise host and you send `github_token`. |
| `options` | object | no | What to copy; each is `true` by default: `issues` (issues and pull requests with comments and reviews), `labels` (labels and milestones), `branch_protection`, `variables` (Actions variables, secret names and deployment environments), `releases`, `lfs`. Plus `secrets`: `bypass` (default: credentials found in old history are imported with an audited push protection bypass, which needs a person with admin on the target and an `admin` token or browser session) or `stop` (the import fails). Unknown keys are refused with 422. |
| `repositories` | string[] | no | `source_owner` only: the repository names to import, at most 1,000. Default: every repository (up to 1,000). |
| `exclude_forks` | boolean | no | `source_owner` only: skip forks (default `false`). |
| `exclude_archived` | boolean | no | `source_owner` only: skip archived repositories (default `false`). |
| `concurrency` | integer | no | `source_owner` only: repositories imported at the same time, 1 to 8 (default 3). |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/imports" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"owner":"..."}'
```

### Get an import

```http
GET /api/v3/diffinery/imports/{id}
```

Readable by the person or agent who started it, by people who could start an import into the same target (the account itself, or the organization's owners and admins), and by site administrators; others get 404 `import not found`. Fields: `kind` (`repository` or `organization`), `status` (`draft`, `queued`, `running`, `succeeded`, `failed` or `cancelled`), `attempt`, `source`, `target`, `visibility`, `options`, `steps` (each with `name`, `title`, `status`, `message`, `count` and times), `git` (the transfer's `phase`, `message`, `chunks`, `bytes` and `tries`), `summary` (counts, secret names, variables, environments, releases, push protection `findings`, linked and imported people), `warnings`, `error` and timestamps. An organization import adds `children` (each repository import's `id`, `source`, `target`, `status`, current `step` and `error`), and a draft adds `candidates`. Credentials are never included. Poll until `status` is `succeeded`, `failed` or `cancelled`.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/diffinery/imports/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Report a Git transfer's result (import agent)

```http
POST /api/v3/diffinery/imports/{id}/agent/complete
```

Internal: the import agent reports the result (branches, tags, pull request heads, LFS objects, push protection findings, warnings). Revokes the push token and wakes the import's workflow. Same credential rules as the spec. 204.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/imports/1/agent/complete" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Report Git transfer progress (import agent)

```http
POST /api/v3/diffinery/imports/{id}/agent/progress
```

Internal: the import agent reports its phase, a message, and the chunks and bytes pushed so far. Same credential rules as the spec. 204.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/imports/1/agent/progress" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a Git transfer spec (import agent)

```http
GET /api/v3/diffinery/imports/{id}/agent/spec
```

Internal: called by the import container with the import's own push token, which works only on Git, Git LFS and these agent endpoints. Says what to clone and where to push, and includes the GitHub token, so no other credential is accepted (403 `this token does not belong to this import`, or 403 `this push token is no longer current for the import` for a token from an earlier try; 409 `this import is not running`).

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/diffinery/imports/1/agent/spec" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Cancel an import

```http
POST /api/v3/diffinery/imports/{id}/cancel
```

Stops a `draft`, `queued` or `running` import (409 `the import already <status>` otherwise): ends its workflow and container and revokes its push tokens. Cancelling an organization import cancels its unfinished repository imports. A repository the import already created is kept with what was copied so far, and is unlocked. Anyone who can read the import can cancel it. Audited as `import.cancel`.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/imports/1/cancel" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Claim an import's Git transfer (local development)

```http
POST /api/v3/diffinery/imports/{id}/claim
```

Only when the Worker runs with `IMPORT_GIT_AGENT=external` (the `dev` environment, where containers don't run); 404 otherwise. Whoever started the import gets `{ token }`, a push token for the transfer, and runs the runner image's import mode by hand with `DIFFINERY_API_URL`, `DIFFINERY_IMPORT_ID` and `DIFFINERY_IMPORT_TOKEN`. 409 `this import is not waiting for an agent`.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/imports/1/claim" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Retry an import

```http
POST /api/v3/diffinery/imports/{id}/retry
```

Runs a `failed` or `cancelled` import again as a new `attempt` (409 `only failed or cancelled imports can be retried` otherwise), with the same options. Only whoever started it can retry it (404 for anyone else), except that a person who may import into the target can also retry an import an agent started. A repository import inside an organization import can't be retried on its own (422 `retry the organization import this repository belongs to`); retrying the organization import re-runs its failed and cancelled repositories, except those that failed because the target name was taken. The GitHub token was deleted when the import ended, so send `github_token` again for a private source. The retry resumes into the repository the import created, and fails if someone else has written to it since (`repository already holds content not written by this import; start a new import`). An agent can't retry once the repository exists (403 `an agent cannot retry an import after the repository was created; a person who administers <owner> must retry it`). Audited as `import.retry`.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories. **Success:** `202`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `github_token` | string | no | A GitHub token for this attempt (optional; at most 400 characters). |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/imports/1/retry" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Choose repositories for a draft import

```http
POST /api/v3/diffinery/imports/{id}/selection
```

An organization import started from the web form waits as a `draft` with its `candidates` until its repositories are chosen; this starts it. Names are matched to the candidates ignoring case, and names that aren't candidates are dropped. 422 `choose at least one repository`, 409 `this import has already started`. Only whoever started it (404 for anyone else). Imports started through this API or MCP never wait as drafts. Unstarted drafts are cancelled after 7 days. Audited as `import.create`.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories. **Success:** `202`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `repositories` | string[] | yes | Names of the repositories to import, at most 1,000. |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/imports/1/selection" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"repositories":["..."]}'
```

### List your linked GitHub accounts

```http
GET /api/v3/diffinery/user/linked-accounts
```

Each link has `id`, `host` (`github.com` or the Enterprise host), `apiBase`, `login`, `externalId` (GitHub's numeric user id) and `createdAt`. Imports attribute a GitHub user's issues, pull requests, comments, reviews and releases to the Diffinery account linked to that user id on the same API base. Everyone else is imported as a mannequin: login `github:<login>`, `type: "Mannequin"`, linking to the GitHub profile.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/diffinery/user/linked-accounts" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Unlink a GitHub account

```http
DELETE /api/v3/diffinery/user/linked-accounts/{id}
```

Removes one of your own links (an id that isn't yours changes nothing). Imports that already ran keep their attribution. Audited as `account.unlink_github`.

**Access:** Any active account (a token, or a browser session). Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/diffinery/user/linked-accounts/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Link a GitHub account

```http
POST /api/v3/diffinery/user/linked-accounts/github
```

Step 2: reads the GitHub user's public profile and public gists without a token on the same API base, and links the account when one of the first 100 public gists GitHub lists for the user has your nonce in its description or in a file (file contents are read for at most 20 gists). Returns `{ id, host, login }`. 422 `create a PUBLIC gist whose description or a file contains <nonce>, then try again`, 422 `GitHub user <login> was not found`, 409 `GitHub user <login> is linked to another Diffinery account`, 429 when GitHub's rate limit is reached. People only. Audited as `account.link_github`.

**Access:** Any active account (a token, or a browser session). Tokens need the `admin` scope and access to all repositories. **Success:** `201`.

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `login` | string | yes | Your GitHub username. |
| `api_url` | string | no | The same API base you used for the challenge. Default: github.com. |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/user/linked-accounts/github" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"login":"..."}'
```

### Get a GitHub link code

```http
POST /api/v3/diffinery/user/linked-accounts/github/challenge
```

Step 1 of linking a GitHub account without a token: returns `nonce` (`diffinery-link-` and 32 hex characters, the same each time for your account and host), `apiBase`, `host` and `gistsUrl`. Put the nonce in the description or a file of a public gist of the GitHub account, then call `POST /diffinery/user/linked-accounts/github`. People only (403 `only people can link GitHub accounts`).

**Access:** Any active account (a token, or a browser session). Tokens need the `admin` scope and access to all repositories.

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `api_url` | string | no | GitHub Enterprise REST API base, such as `https://ghe.example.com/api/v3`. Default: github.com. |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/user/linked-accounts/github/challenge" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Status page

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/diffinery/admin/status/incidents` | [List status incidents](#list-status-incidents) |
| POST | `/diffinery/admin/status/incidents` | [Open a status incident](#open-a-status-incident) |
| POST | `/diffinery/admin/status/incidents/{id}/updates` | [Post an update to a status incident](#post-an-update-to-a-status-incident) |
| GET | `/diffinery/status` | [Get the instance's status](#get-the-instances-status) |

### List status incidents

```http
GET /api/v3/diffinery/admin/status/incidents
```

Incidents on the status page, newest first, resolved or not: `id`, `title`, `impact`, `state`, `components`, `created_by`, `created_at`, `updated_at`, `resolved_at`, `updates` (each with `id`, `state`, `body`, `author` and `created_at`, newest first) and `html_url`. 404 for anyone but a site administrator.

**Access:** A site administrator. Tokens need the `read` scope and access to all repositories.

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | At most this many (default 50, up to 200). |

```sh
curl "https://diffinery.com/api/v3/diffinery/admin/status/incidents" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Open a status incident

```http
POST /api/v3/diffinery/admin/status/incidents
```

Opens an incident with its first update and answers with it. While it isn't resolved, its impact sets the status of each component it names: `critical` is a major outage, `major` a partial outage, `minor` degraded performance and `maintenance` under maintenance. Recorded in the audit log as `status_incident.create`. 404 for anyone but a site administrator.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories. **Success:** `201`.

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | yes | One line, up to 200 characters. |
| `impact` | string | yes | `minor`, `major`, `critical` or `maintenance`. |
| `components` | array | yes | At least one of `web`, `git`, `actions`, `agents`, `packages` and `email`. |
| `state` | string | yes | `investigating`, `identified`, `monitoring` or `resolved`. |
| `body` | string | yes | The first update, plain text up to 5,000 characters. It is public. |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/admin/status/incidents" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"...","impact":"...","components":[],"state":"...","body":"..."}'
```

### Post an update to a status incident

```http
POST /api/v3/diffinery/admin/status/incidents/{id}/updates
```

Adds an update and moves the incident to its state; `resolved` resolves it, and any other state reopens a resolved incident. Answers with the incident. Recorded in the audit log as `status_incident.resolve` when it resolves the incident and `status_incident.update` otherwise. 404 when there is no such incident, or for anyone but a site administrator.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | yes | `investigating`, `identified`, `monitoring` or `resolved`. |
| `body` | string | yes | Plain text up to 5,000 characters. It is public. |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/admin/status/incidents/1/updates" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"state":"...","body":"..."}'
```

### Get the instance's status

```http
GET /api/v3/diffinery/status
```

The status page as JSON, shaped like Statuspage's summary: `status` (`indicator`: `none`, `minor`, `major`, `critical` or `maintenance`, and a `description`), `components` (`id`, `name`, `status`: `operational`, `under_maintenance`, `degraded_performance`, `partial_outage` or `major_outage`, and a `note` when a kill switch or a database failure set it), `incidents` (the unresolved ones, newest first, each with its `updates`, newest first) and `updated_at`. Cached for 30 seconds. See [Status page](https://diffinery.com/docs/self-hosting/status-page).

**Access:** No authentication needed.

```sh
curl "https://diffinery.com/api/v3/diffinery/status"
```

## Notifications and email

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/diffinery/admin/early-access` | [List early access requests](#list-early-access-requests) |
| GET | `/diffinery/admin/early-access/{id}` | [Get an early access request](#get-an-early-access-request) |
| PATCH | `/diffinery/admin/early-access/{id}` | [Decline an early access request, or put it back](#decline-an-early-access-request-or-put-it-back) |
| DELETE | `/diffinery/admin/early-access/{id}` | [Delete an early access request](#delete-an-early-access-request) |
| POST | `/diffinery/admin/early-access/{id}/invite` | [Invite an early access request](#invite-an-early-access-request) |
| GET | `/diffinery/admin/email` | [Email delivery status](#email-delivery-status) |
| GET | `/diffinery/admin/email/suppressions` | [List suppressed email addresses](#list-suppressed-email-addresses) |
| PUT | `/diffinery/admin/email/suppressions/{email}` | [Suppress an email address](#suppress-an-email-address) |
| DELETE | `/diffinery/admin/email/suppressions/{email}` | [Remove an address from the suppression list](#remove-an-address-from-the-suppression-list) |
| POST | `/diffinery/admin/emails/samples` | [Send yourself every email template](#send-yourself-every-email-template) |
| GET | `/diffinery/admin/errors` | [List unexpected server errors](#list-unexpected-server-errors) |
| GET | `/diffinery/admin/errors/{id}` | [Get a server error by its request ID](#get-a-server-error-by-its-request-id) |
| GET | `/diffinery/admin/indexnow` | [IndexNow submissions](#indexnow-submissions) |
| GET | `/diffinery/admin/scheduler` | [Workflow scheduler state](#workflow-scheduler-state) |
| GET | `/diffinery/admin/security-reports` | [List security reports](#list-security-reports) |
| GET | `/diffinery/admin/security-reports/{id}` | [Get a security report](#get-a-security-report) |
| PATCH | `/diffinery/admin/security-reports/{id}` | [Triage or resolve a security report](#triage-or-resolve-a-security-report) |
| GET | `/diffinery/emails` | [List emails sent to you](#list-emails-sent-to-you) |
| POST | `/diffinery/emails/digest` | [Send yourself the morning digest now](#send-yourself-the-morning-digest-now) |
| POST | `/diffinery/emails/test` | [Send yourself a test email](#send-yourself-a-test-email) |
| GET | `/diffinery/notification-settings` | [Get your notification settings](#get-your-notification-settings) |
| PUT | `/diffinery/notification-settings` | [Update your notification settings](#update-your-notification-settings) |
| GET | `/notifications` | [List notifications](#list-notifications) |
| PUT | `/notifications` | [Mark all notifications as read](#mark-all-notifications-as-read) |
| GET | `/repos/{owner}/{repo}/subscription` | [Get your watch setting](#get-your-watch-setting) |
| PUT | `/repos/{owner}/{repo}/subscription` | [Watch or ignore a repository](#watch-or-ignore-a-repository) |
| DELETE | `/repos/{owner}/{repo}/subscription` | [Stop watching a repository](#stop-watching-a-repository) |

### List early access requests

```http
GET /api/v3/diffinery/admin/early-access
```

Requests sent through `/early-access`, newest first: `id`, `state` (`unconfirmed` until the address follows the emailed link, then `confirmed`, `invited` or `declined`), `email`, `name`, `company`, `use_case`, `hosting` (`github`, `gitlab`, `bitbucket`, `azure`, `self-hosted`, `other`, `none` or null), `confirmed_at`, `invite_id`, `decided_by`, `decided_at`, `created_at`, `updated_at` and `html_url`. 404 for anyone but a site administrator. See [Early access](https://diffinery.com/docs/accounts/early-access).

**Access:** A site administrator. Tokens need the `read` scope and access to all repositories.

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | no | Only requests in this state: `confirmed`, `unconfirmed`, `invited` or `declined`. |
| `q` | string | no | Only requests whose address, name, company or use contains this text. |
| `per_page` | integer | no | At most this many (default 100, up to 500). |
| `page` | integer | no | Page number, from 1. |

```sh
curl "https://diffinery.com/api/v3/diffinery/admin/early-access" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get an early access request

```http
GET /api/v3/diffinery/admin/early-access/{id}
```

One request, as in the list. 404 when there is none, or for anyone but a site administrator.

**Access:** A site administrator. Tokens need the `read` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/diffinery/admin/early-access/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Decline an early access request, or put it back

```http
PATCH /api/v3/diffinery/admin/early-access/{id}
```

`declined` declines it; `confirmed` puts a declined request back (as `unconfirmed` if its address never confirmed). Nobody is emailed. Recorded in the audit log as `early_access.decline` or `early_access.restore`. 404 for anyone but a site administrator.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | yes | `declined`, or `confirmed` to put a declined request back. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/diffinery/admin/early-access/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"state":"..."}'
```

### Delete an early access request

```http
DELETE /api/v3/diffinery/admin/early-access/{id}
```

Removes the request, for someone who asks for their data to be removed. An invitation already sent from it stays; revoke it separately. Recorded in the audit log as `early_access.delete`, without the request's content or address. 404 for anyone but a site administrator.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/diffinery/admin/early-access/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Invite an early access request

```http
POST /api/v3/diffinery/admin/early-access/{id}/invite
```

Sends the request's address the instance's usual invitation email (it works once for 14 days) and marks the request `invited`. An address that already has a pending instance invitation keeps it; one that already belongs to an active account is refused (422). Recorded in the audit log as `early_access.invite`, and `invite.create` when a new invitation is sent. 404 for anyone but a site administrator.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/admin/early-access/1/invite" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Email delivery status

```http
GET /api/v3/diffinery/admin/email
```

Whether sending is configured, whether the signed bounce and complaint endpoint is on (`event_intake`), and counts for the last 24 hours.

**Access:** A site administrator. Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/diffinery/admin/email" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List suppressed email addresses

```http
GET /api/v3/diffinery/admin/email/suppressions
```

Newest first: `email`, `reason` (`hard-bounce`, `complaint` or `manual`), `detail`, `source` (`cloudflare`, `webhook`, `send` or `admin`), `created_by` and `created_at`.

**Access:** A site administrator. Tokens need the `read` scope and access to all repositories.

```sh
curl "https://diffinery.com/api/v3/diffinery/admin/email/suppressions" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Suppress an email address

```http
PUT /api/v3/diffinery/admin/email/suppressions/{email}
```

Diffinery sends nothing to it until it is removed. Recorded in the audit log.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string | yes | email |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `note` | string | no | Why, kept with the entry. |

```sh
curl -X PUT "https://diffinery.com/api/v3/diffinery/admin/email/suppressions/email" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Remove an address from the suppression list

```http
DELETE /api/v3/diffinery/admin/email/suppressions/{email}
```

Whatever put it there. 404 when it isn't suppressed. Recorded in the audit log.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string | yes | email |

```sh
curl -X DELETE "https://diffinery.com/api/v3/diffinery/admin/email/suppressions/email" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Send yourself every email template

```http
POST /api/v3/diffinery/admin/emails/samples
```

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories.

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `only` | string[] | no | Only these sample ids. |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/admin/emails/samples" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List unexpected server errors

```http
GET /api/v3/diffinery/admin/errors
```

The newest answers with a 5xx status, newest first: `id` (the `request_id` the answer carried, also in its `x-request-id` header), `at`, `method`, `route`, `path`, `status`, `message` and `stack`. The newest 500 are kept. No request bodies, query strings or headers are kept, and tokens in a message are masked.

**Access:** A site administrator. Tokens need the `read` scope.

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | At most this many (default 100, up to 500). |

```sh
curl "https://diffinery.com/api/v3/diffinery/admin/errors" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a server error by its request ID

```http
GET /api/v3/diffinery/admin/errors/{id}
```

The error a 5xx answer with this `request_id` recorded; 404 once it is no longer among the newest 500.

**Access:** A site administrator. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/diffinery/admin/errors/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### IndexNow submissions

```http
GET /api/v3/diffinery/admin/indexnow
```

What this instance has told search engines through IndexNow: `enabled` (and `off_reason` when it isn't), `key_location`, how many `site_pages` and public `repositories` it tracks, how many are `queued`, `retry_at` (set after IndexNow refused or couldn't be reached), `repositories_checked_at`, and the newest `submissions` (`at`, `urls`, `status` from IndexNow or null when unreachable, `endpoint` (the host that answered), `ms`, `error`, and the first 50 `paths`). See [Search engines](https://diffinery.com/docs/admin/site-administration#search-engines).

**Access:** A site administrator. Tokens need the `read` scope.

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `per_page` | integer | no | Submissions to return (default 50, up to 200). |

```sh
curl "https://diffinery.com/api/v3/diffinery/admin/indexnow" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Workflow scheduler state

```http
GET /api/v3/diffinery/admin/scheduler
```

`tick_minutes`, `last_tick_at` (when the last check finished), `covered_until` (the last minute whose schedules were started) and `next_tick_at` (null when the timer isn't set). Tells a scheduler that stopped ticking from a run that failed to start.

**Access:** A site administrator. Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/diffinery/admin/scheduler" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List security reports

```http
GET /api/v3/diffinery/admin/security-reports
```

Private vulnerability reports sent through `/security/report`, newest first: `id`, `state` (`new`, `triaged` or `resolved`), `summary`, `details`, `area`, `reply_to`, `reporter` (a login, or null when not signed in), `note`, `updated_by`, `updated_at`, `created_at` and `html_url`. 404 for anyone but a site administrator.

**Access:** A site administrator. Tokens need the `read` scope and access to all repositories.

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | no | Only reports in this state: `new`, `triaged` or `resolved`. |
| `per_page` | integer | no | At most this many (default 100, up to 500). |

```sh
curl "https://diffinery.com/api/v3/diffinery/admin/security-reports" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a security report

```http
GET /api/v3/diffinery/admin/security-reports/{id}
```

One report, as in the list. 404 when there is none, or for anyone but a site administrator.

**Access:** A site administrator. Tokens need the `read` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/diffinery/admin/security-reports/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Triage or resolve a security report

```http
PATCH /api/v3/diffinery/admin/security-reports/{id}
```

Sets the report's state and note (a missing or empty note clears it). Recorded in the audit log as `security_report.triage`, `security_report.resolve` or `security_report.reopen`. 404 for anyone but a site administrator.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | yes | `triaged`, `resolved`, or `new` to reopen it. |
| `note` | string | no | For the other site administrators, up to 2,000 characters. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/diffinery/admin/security-reports/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"state":"..."}'
```

### List emails sent to you

```http
GET /api/v3/diffinery/emails
```

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `kind` | string | no | Only this kind of email. |
| `since` | string | no | ISO timestamp. |
| `per_page` | integer | no | At most this many (default 50). |
| `all` | string | no | `1` for everyone's (site admins). |

```sh
curl "https://diffinery.com/api/v3/diffinery/emails" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Send yourself the morning digest now

```http
POST /api/v3/diffinery/emails/digest
```

Your Today digest, sent now even when the digest is off or has nothing in it, covering what happened since the last one. At most 3 an hour; more answer 429. See /docs/agents/today#the-morning-digest.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories.

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/emails/digest" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Send yourself a test email

```http
POST /api/v3/diffinery/emails/test
```

At most 5 an hour; more answer 429 `you can send at most 5 test emails an hour; try again later`.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories.

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/emails/test" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get your notification settings

```http
GET /api/v3/diffinery/notification-settings
```

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/diffinery/notification-settings" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update your notification settings

```http
PUT /api/v3/diffinery/notification-settings
```

Send only the groups you want to change. The morning digest is `digest`: `email` (on or off), `hour` (0 to 23), `timeZone` (an IANA time zone such as `Europe/Istanbul` or `UTC`) and `weekends`; 422 for an hour or time zone it can't use. See /docs/agents/today#the-morning-digest.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories.

```sh
curl -X PUT "https://diffinery.com/api/v3/diffinery/notification-settings" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List notifications

```http
GET /api/v3/notifications
```

A token limited to repositories answers 403 `this token is limited to repositories and can't read notifications`, since notifications cover every repository.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `all` | boolean | no | `true` to include read ones. |

```sh
curl "https://diffinery.com/api/v3/notifications" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Mark all notifications as read

```http
PUT /api/v3/notifications
```

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories. **Success:** `205`.

```sh
curl -X PUT "https://diffinery.com/api/v3/notifications" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get your watch setting

```http
GET /api/v3/repos/{owner}/{repo}/subscription
```

404 when you only get participating notifications (the default), as on GitHub.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/subscription" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Watch or ignore a repository

```http
PUT /api/v3/repos/{owner}/{repo}/subscription
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `subscribed` | boolean | no | `true` for all activity, `false` for participating only. |
| `ignored` | boolean | no | `true` to ignore the repository. |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/subscription" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Stop watching a repository

```http
DELETE /api/v3/repos/{owner}/{repo}/subscription
```

Back to participating notifications.

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/subscription" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Tokens and agents

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/diffinery/agents` | [List your agents](#list-your-agents) |
| POST | `/diffinery/agents` | [Create an agent](#create-an-agent) |
| DELETE | `/diffinery/agents/{login}` | [Disable an agent](#disable-an-agent) |
| PUT | `/diffinery/agents/{login}/auto-merge` | [Turn auto-merge on or off for an agent's pull requests](#turn-auto-merge-on-or-off-for-an-agents-pull-requests) |
| POST | `/diffinery/agents/{login}/tokens` | [Create a token for an agent](#create-a-token-for-an-agent) |
| GET | `/diffinery/tokens` | [List your tokens](#list-your-tokens) |
| POST | `/diffinery/tokens` | [Create a token](#create-a-token) |
| DELETE | `/diffinery/tokens/{id}` | [Revoke a token](#revoke-a-token) |

### List your agents

```http
GET /api/v3/diffinery/agents
```

Agents you own, and agents of organizations you administer.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/diffinery/agents" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create an agent

```http
POST /api/v3/diffinery/agents
```

People, from a browser session only (no token can create a token). Returns the agent and its first token (write scope, 90 days, unless you say otherwise). Unknown scopes or an empty list fail with 422. From a browser session whose sign-in is more than 2 hours old: 403 `Confirm it's you: sign in with your passkey again to do this.` with a `confirm` URL (see /docs/security/overview#confirming-its-you).

**Access:** Any active account (a token, or a browser session). No token can call it: it needs a browser session. **Success:** `201`.

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `login` | string | yes | Agent login. |
| `name` | string | no | Display name. |
| `org` | string | no | Organization that owns the agent (default: you). |
| `policy` | object | no | Agent policy. |
| `token` | object | no | `{ scopes, expires_in_days }` for the first token. |
| `auto_merge` | boolean | no | Turn on auto-merge for the pull requests it opens (see `PUT /diffinery/agents/{login}/auto-merge`). |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/agents" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"login":"..."}'
```

### Disable an agent

```http
DELETE /api/v3/diffinery/agents/{login}
```

Its tokens stop working.

**Access:** Any active account (a token, or a browser session). Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `login` | string | yes | Account login. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/diffinery/agents/diffy" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Turn auto-merge on or off for an agent's pull requests

```http
PUT /api/v3/diffinery/agents/{login}/auto-merge
```

The agent's owner, or an owner or admin of the organization that owns it. Diffinery then turns on auto-merge, as the agent, for each pull request it opens; it lands only as the agent's own auto-merge would (the repository must allow agents' auto-merge, or the agent may merge what a person approved), and a workflow change still needs a person. Same body as `PUT /diffinery/auto-merge`. Audited as `agent.auto_merge`.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `login` | string | yes | Account login. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `enabled` | boolean | yes | On or off. |
| `merge_method` | string | no | `default`, `merge`, `squash` or `rebase`. |

```sh
curl -X PUT "https://diffinery.com/api/v3/diffinery/agents/diffy/auto-merge" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled":true}'
```

### Create a token for an agent

```http
POST /api/v3/diffinery/agents/{login}/tokens
```

From a browser session only (no token can create a token): the agent's owner, or an owner or admin of the organization that owns it. Default scope `write`; unknown scopes or an empty list fail with 422. Audited as `agent.token.create`. From a browser session whose sign-in is more than 2 hours old: 403 `Confirm it's you: sign in with your passkey again to do this.` with a `confirm` URL (see /docs/security/overview#confirming-its-you).

**Access:** Any active account (a token, or a browser session). No token can call it: it needs a browser session. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `login` | string | yes | Account login. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | no | Token name. |
| `scopes` | string[] | no | `read`, `write` (default) and/or `admin`. |
| `expires_in_days` | integer | no | Lifetime in days. |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/agents/diffy/tokens" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List your tokens

```http
GET /api/v3/diffinery/tokens
```

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/diffinery/tokens" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a token

```http
POST /api/v3/diffinery/tokens
```

From a browser session only: no token can create a token. The token value is returned once. Unknown scopes or an empty list fail with 422, and so does a repository you can't see (`unknown repository owner/name`). From a browser session whose sign-in is more than 2 hours old: 403 `Confirm it's you: sign in with your passkey again to do this.` with a `confirm` URL (see /docs/security/overview#confirming-its-you).

**Access:** Any active account (a token, or a browser session). No token can call it: it needs a browser session. **Success:** `201`.

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | yes | A name to recognise it by. |
| `scopes` | string[] | no | `read`, `write` (default) and/or `admin`. |
| `repositories` | string[] | no | Restrict to these `owner/name` repositories (only ones you can see). |
| `expires_in_days` | integer | no | Lifetime in days. |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/tokens" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"..."}'
```

### Revoke a token

```http
DELETE /api/v3/diffinery/tokens/{id}
```

**Access:** Any active account (a token, or a browser session). Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/diffinery/tokens/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Sandboxes

| Method | Path | Summary |
| --- | --- | --- |
| POST | `/repos/{owner}/{repo}/diffinery/sandboxes` | [Start a sandbox](#start-a-sandbox) |
| POST | `/repos/{owner}/{repo}/diffinery/sandboxes/{id}/{action}` | [Use a sandbox](#use-a-sandbox) |

### Start a sandbox

```http
POST /api/v3/repos/{owner}/{repo}/diffinery/sandboxes
```

A container with the repository checked out, for agents to build and test in.

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `ref` | string | no | Branch, tag or commit to check out (default: the default branch). |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/diffinery/sandboxes" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Use a sandbox

```http
POST /api/v3/repos/{owner}/{repo}/diffinery/sandboxes/{id}/{action}
```

`action` is `exec` (run a command), `read` or `write` (files), or `close`.

**Access:** Write access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |
| `action` | string | yes | Action to take. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/diffinery/sandboxes/1/exec" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Other

| Method | Path | Summary |
| --- | --- | --- |
| GET | `/admin/accounts/{login}/actions-suspension` | [Get an account's Actions suspension](#get-an-accounts-actions-suspension) |
| PUT | `/admin/accounts/{login}/actions-suspension` | [Suspend Actions for an account](#suspend-actions-for-an-account) |
| DELETE | `/admin/accounts/{login}/actions-suspension` | [Lift an account's Actions suspension](#lift-an-accounts-actions-suspension) |
| GET | `/admin/accounts/{login}/quotas` | [Get an account's quotas and usage](#get-an-accounts-quotas-and-usage) |
| PATCH | `/admin/accounts/{login}/quotas` | [Change an account's quotas](#change-an-accounts-quotas) |
| GET | `/admin/hosted-compute-pause` | [Get the hosted compute pause](#get-the-hosted-compute-pause) |
| PUT | `/admin/hosted-compute-pause` | [Pause hosted compute](#pause-hosted-compute) |
| DELETE | `/admin/hosted-compute-pause` | [Resume hosted compute](#resume-hosted-compute) |
| GET | `/admin/reports` | [List reports](#list-reports) |
| GET | `/admin/reports/{id}` | [Get a report](#get-a-report) |
| PATCH | `/admin/reports/{id}` | [Resolve or reopen a report](#resolve-or-reopen-a-report) |
| GET | `/admin/repos/{owner}/{repo}/actions-suspension` | [Get a repository's Actions suspension](#get-a-repositorys-actions-suspension) |
| PUT | `/admin/repos/{owner}/{repo}/actions-suspension` | [Suspend Actions for a repository](#suspend-actions-for-a-repository) |
| DELETE | `/admin/repos/{owner}/{repo}/actions-suspension` | [Lift a repository's Actions suspension](#lift-a-repositorys-actions-suspension) |
| GET | `/app` | [List app](#list-app) |
| GET | `/app/installations` | [List installations](#list-installations) |
| GET | `/app/installations/{id}` | [Get a installation](#get-a-installation) |
| DELETE | `/app/installations/{id}` | [Delete a installation](#delete-a-installation) |
| POST | `/app/installations/{id}/access_tokens` | [Create a access token](#create-a-access-token) |
| PUT | `/app/installations/{id}/suspended` | [Set suspended](#set-suspended) |
| DELETE | `/app/installations/{id}/suspended` | [Delete suspended](#delete-suspended) |
| GET | `/apps/{slug}` | [Get a app](#get-a-app) |
| GET | `/diffinery/apps` | [List apps](#list-apps) |
| POST | `/diffinery/apps` | [Create a app](#create-a-app) |
| GET | `/diffinery/apps/{slug}` | [Get a app](#get-a-app-get-diffineryappsslug) |
| PATCH | `/diffinery/apps/{slug}` | [Update a app](#update-a-app) |
| DELETE | `/diffinery/apps/{slug}` | [Delete a app](#delete-a-app) |
| POST | `/diffinery/apps/{slug}/installations` | [Create a installation](#create-a-installation) |
| GET | `/diffinery/apps/{slug}/keys` | [List keys](#list-keys) |
| POST | `/diffinery/apps/{slug}/keys` | [Create a key](#create-a-key) |
| DELETE | `/diffinery/apps/{slug}/keys/{keyId}` | [Delete a key](#delete-a-key) |
| GET | `/diffinery/auto-merge` | [Your auto-merge setting](#your-auto-merge-setting) |
| PUT | `/diffinery/auto-merge` | [Turn auto-merge on or off for pull requests you open](#turn-auto-merge-on-or-off-for-pull-requests-you-open) |
| GET | `/diffinery/email` | [Your email address and whether it is suppressed](#your-email-address-and-whether-it-is-suppressed) |
| POST | `/diffinery/email/verification` | [Ask for the email that turns email back on](#ask-for-the-email-that-turns-email-back-on) |
| GET | `/diffinery/installations/{id}` | [Get a installation](#get-a-installation-get-diffineryinstallationsid) |
| PATCH | `/diffinery/installations/{id}` | [Update a installation](#update-a-installation) |
| DELETE | `/diffinery/installations/{id}` | [Delete a installation](#delete-a-installation-delete-diffineryinstallationsid) |
| POST | `/diffinery/installations/{id}/accept_permissions` | [Create a accept permission](#create-a-accept-permission) |
| PUT | `/diffinery/installations/{id}/suspended` | [Set suspended](#set-suspended-put-diffineryinstallationsidsuspended) |
| DELETE | `/diffinery/installations/{id}/suspended` | [Delete suspended](#delete-suspended-delete-diffineryinstallationsidsuspended) |
| GET | `/diffinery/model-keys` | [List your model keys](#list-your-model-keys) |
| PUT | `/diffinery/model-keys/{provider}` | [Save a model key](#save-a-model-key) |
| DELETE | `/diffinery/model-keys/{provider}` | [Delete a model key](#delete-a-model-key) |
| GET | `/diffinery/model-usage` | [Get your model usage](#get-your-model-usage) |
| POST | `/diffinery/reports` | [Report content to the site administrators](#report-content-to-the-site-administrators) |
| GET | `/diffinery/tasks` | [List your agent tasks](#list-your-agent-tasks) |
| GET | `/diffinery/today` | [Your morning view](#your-morning-view) |
| GET | `/installation/repositories` | [List repositories](#list-repositories) |
| DELETE | `/installation/token` | [Delete token](#delete-token) |
| GET | `/orgs/{org}/blocks` | [List the people an organization blocked](#list-the-people-an-organization-blocked) |
| GET | `/orgs/{org}/blocks/{username}` | [Check whether an organization blocked a person](#check-whether-an-organization-blocked-a-person) |
| PUT | `/orgs/{org}/blocks/{username}` | [Block a person from an organization](#block-a-person-from-an-organization) |
| DELETE | `/orgs/{org}/blocks/{username}` | [Unblock a person from an organization](#unblock-a-person-from-an-organization) |
| GET | `/orgs/{org}/diffinery/agent-policy` | [Get an organization's agent policy](#get-an-organizations-agent-policy) |
| PUT | `/orgs/{org}/diffinery/agent-policy` | [Change an organization's agent policy](#change-an-organizations-agent-policy) |
| GET | `/orgs/{org}/diffinery/model-keys` | [List an organization's model keys](#list-an-organizations-model-keys) |
| PUT | `/orgs/{org}/diffinery/model-keys/{provider}` | [Save an organization's model key](#save-an-organizations-model-key) |
| DELETE | `/orgs/{org}/diffinery/model-keys/{provider}` | [Delete an organization's model key](#delete-an-organizations-model-key) |
| GET | `/orgs/{org}/diffinery/model-usage` | [Get an organization's model usage](#get-an-organizations-model-usage) |
| GET | `/orgs/{org}/installation` | [List installation](#list-installation) |
| GET | `/orgs/{org}/usage` | [Get an organization's quotas and usage](#get-an-organizations-quotas-and-usage) |
| GET | `/repos/{owner}/{repo}/diffinery/agent-review` | [Get agent review settings](#get-agent-review-settings) |
| PUT | `/repos/{owner}/{repo}/diffinery/agent-review` | [Turn agent review on, change or off](#turn-agent-review-on-change-or-off) |
| GET | `/repos/{owner}/{repo}/diffinery/agent-setup` | [Get the agent setup check](#get-the-agent-setup-check) |
| POST | `/repos/{owner}/{repo}/diffinery/agent-setup/checks` | [Report an agent setup check](#report-an-agent-setup-check) |
| PUT | `/repos/{owner}/{repo}/diffinery/comments/{id}/minimized` | [Hide (minimize) a comment](#hide-minimize-a-comment) |
| DELETE | `/repos/{owner}/{repo}/diffinery/comments/{id}/minimized` | [Show a hidden comment again](#show-a-hidden-comment-again) |
| POST | `/repos/{owner}/{repo}/diffinery/delete-closed-pulls` | [Delete closed pull requests](#delete-closed-pull-requests) |
| GET | `/repos/{owner}/{repo}/diffinery/project` | [Get the project](#get-the-project) |
| GET | `/repos/{owner}/{repo}/diffinery/project/coordinator` | [Get your coordinator](#get-your-coordinator) |
| PUT | `/repos/{owner}/{repo}/diffinery/project/coordinator` | [Turn on or change your coordinator](#turn-on-or-change-your-coordinator) |
| DELETE | `/repos/{owner}/{repo}/diffinery/project/coordinator` | [Turn off your coordinator](#turn-off-your-coordinator) |
| GET | `/repos/{owner}/{repo}/diffinery/project/coordinators` | [List the coordinators in a project](#list-the-coordinators-in-a-project) |
| GET | `/repos/{owner}/{repo}/diffinery/project/memory` | [Get the project memory](#get-the-project-memory) |
| PUT | `/repos/{owner}/{repo}/diffinery/project/memory` | [Save or restore the project memory](#save-or-restore-the-project-memory) |
| GET | `/repos/{owner}/{repo}/diffinery/project/posts` | [List the project conversation](#list-the-project-conversation) |
| POST | `/repos/{owner}/{repo}/diffinery/project/posts` | [Post to the project conversation](#post-to-the-project-conversation) |
| POST | `/repos/{owner}/{repo}/diffinery/project/posts/{n}/handle` | [Hand a post to your coordinator](#hand-a-post-to-your-coordinator) |
| PUT | `/repos/{owner}/{repo}/diffinery/project/settings` | [Change the project settings](#change-the-project-settings) |
| POST | `/repos/{owner}/{repo}/diffinery/purge-unreachable` | [Purge unreachable objects](#purge-unreachable-objects) |
| GET | `/repos/{owner}/{repo}/diffinery/tasks` | [List agent tasks](#list-agent-tasks) |
| POST | `/repos/{owner}/{repo}/diffinery/tasks` | [Start an agent task](#start-an-agent-task) |
| GET | `/repos/{owner}/{repo}/diffinery/tasks/{number}` | [Get an agent task](#get-an-agent-task) |
| PATCH | `/repos/{owner}/{repo}/diffinery/tasks/{number}` | [Change a task's options](#change-a-tasks-options) |
| GET | `/repos/{owner}/{repo}/diffinery/tasks/{number}/attempts` | [Compare a task's attempts](#compare-a-tasks-attempts) |
| POST | `/repos/{owner}/{repo}/diffinery/tasks/{number}/attempts/{attempt}/pick` | [Pick a task's attempt](#pick-a-tasks-attempt) |
| POST | `/repos/{owner}/{repo}/diffinery/tasks/{number}/messages` | [Send a task a follow-up](#send-a-task-a-follow-up) |
| POST | `/repos/{owner}/{repo}/diffinery/tasks/{number}/plan/approve` | [Approve a task's plan](#approve-a-tasks-plan) |
| POST | `/repos/{owner}/{repo}/diffinery/tasks/{number}/plan/split` | [Split a task's plan into tasks](#split-a-tasks-plan-into-tasks) |
| POST | `/repos/{owner}/{repo}/diffinery/tasks/{number}/retry` | [Retry a task](#retry-a-task) |
| POST | `/repos/{owner}/{repo}/diffinery/tasks/{number}/stop` | [Stop a task](#stop-a-task) |
| GET | `/repos/{owner}/{repo}/diffinery/tasks/{number}/transcript` | [Read a task's transcript](#read-a-tasks-transcript) |
| GET | `/repos/{owner}/{repo}/installation` | [List installation](#list-installation-get-reposownerrepoinstallation) |
| POST | `/repos/{owner}/{repo}/transfer` | [Transfer a repository](#transfer-a-repository) |
| GET | `/user/blocks` | [List the people you blocked](#list-the-people-you-blocked) |
| GET | `/user/blocks/{username}` | [Check whether you blocked a person](#check-whether-you-blocked-a-person) |
| PUT | `/user/blocks/{username}` | [Block a person](#block-a-person) |
| DELETE | `/user/blocks/{username}` | [Unblock a person](#unblock-a-person) |
| GET | `/user/installations` | [List installations](#list-installations-get-userinstallations) |
| GET | `/user/installations/{id}/repositories` | [List repositories](#list-repositories-get-userinstallationsidrepositories) |
| PUT | `/user/installations/{id}/repositories/{repoId}` | [Set a repository](#set-a-repository) |
| DELETE | `/user/installations/{id}/repositories/{repoId}` | [Delete a repository](#delete-a-repository-delete-userinstallationsidrepositoriesrepoid) |
| GET | `/user/memberships/orgs` | [List your organization memberships](#list-your-organization-memberships) |
| GET | `/user/memberships/orgs/{org}` | [Get your organization membership](#get-your-organization-membership) |
| PATCH | `/user/memberships/orgs/{org}` | [Accept an organization invitation](#accept-an-organization-invitation) |
| GET | `/user/repository_invitations` | [List your repository invitations](#list-your-repository-invitations) |
| PATCH | `/user/repository_invitations/{id}` | [Accept a repository invitation](#accept-a-repository-invitation) |
| DELETE | `/user/repository_invitations/{id}` | [Decline a repository invitation](#decline-a-repository-invitation) |
| GET | `/user/usage` | [Get your quotas and usage](#get-your-quotas-and-usage) |
| GET | `/users/{username}/installation` | [List installation](#list-installation-get-usersusernameinstallation) |
| PUT | `/users/{username}/suspended` | [Suspend a person](#suspend-a-person) |
| DELETE | `/users/{username}/suspended` | [Unsuspend a person](#unsuspend-a-person) |

### Get an account's Actions suspension

```http
GET /api/v3/admin/accounts/{login}/actions-suspension
```

Site administrators only. `suspended`, `reason`, `suspended_by` and `suspended_at`.

**Access:** A site administrator. Tokens need the `read` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `login` | string | yes | Account login. |

```sh
curl "https://diffinery.com/api/v3/admin/accounts/diffy/actions-suspension" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Suspend Actions for an account

```http
PUT /api/v3/admin/accounts/{login}/actions-suspension
```

Site administrators only. As for a repository, for every repository the person or organization owns; their running runs and sandboxes stop now. Audited as `actions.suspend`.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `login` | string | yes | Account login. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `reason` | string | yes | Why (up to 500 characters). Shown to the people affected and kept in the audit log. |

```sh
curl -X PUT "https://diffinery.com/api/v3/admin/accounts/diffy/actions-suspension" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"reason":"..."}'
```

### Lift an account's Actions suspension

```http
DELETE /api/v3/admin/accounts/{login}/actions-suspension
```

Site administrators only. New work can start again; nothing restarts. Audited as `actions.unsuspend`.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `login` | string | yes | Account login. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/admin/accounts/diffy/actions-suspension" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get an account's quotas and usage

```http
GET /api/v3/admin/accounts/{login}/quotas
```

Site administrators only.

**Access:** A site administrator. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `login` | string | yes | Account login. |

```sh
curl "https://diffinery.com/api/v3/admin/accounts/diffy/quotas" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Change an account's quotas

```http
PATCH /api/v3/admin/accounts/{login}/quotas
```

Site administrators only. Send only the quotas to change: a whole number, `-1` for unlimited, or `null` for the default. Audited as `account.quotas.set`.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `login` | string | yes | Account login. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `hosted_minutes` | integer | no | Hosted minutes per calendar month (UTC). |
| `hosted_jobs` | integer | no | Hosted Actions jobs running at once. |
| `sandboxes` | integer | no | Agent sandboxes open at once. |
| `repositories` | integer | no | Repositories the account owns. |
| `storage_bytes` | integer | no | Bytes stored: git objects, Git LFS objects, release assets and packages, not Actions artifacts or caches. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/admin/accounts/diffy/quotas" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get the hosted compute pause

```http
GET /api/v3/admin/hosted-compute-pause
```

Site administrators only. `paused`, `reason`, `paused_by` and `paused_at`.

**Access:** A site administrator. Tokens need the `read` scope and access to all repositories.

```sh
curl "https://diffinery.com/api/v3/admin/hosted-compute-pause" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Pause hosted compute

```http
PUT /api/v3/admin/hosted-compute-pause
```

Site administrators only. Hosted jobs fail without starting and sandboxes are refused everywhere; running ones stop now. Self-hosted runners still work. Audited as `compute.pause`.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories.

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `reason` | string | yes | Why (up to 500 characters). Shown to the people affected and kept in the audit log. |

```sh
curl -X PUT "https://diffinery.com/api/v3/admin/hosted-compute-pause" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"reason":"..."}'
```

### Resume hosted compute

```http
DELETE /api/v3/admin/hosted-compute-pause
```

Site administrators only. New hosted jobs and sandboxes can start again; nothing restarts. Audited as `compute.unpause`.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories.

```sh
curl -X DELETE "https://diffinery.com/api/v3/admin/hosted-compute-pause" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List reports

```http
GET /api/v3/admin/reports
```

Site administrators only. Newest first, with the reporter, the account reported, the excerpt kept when it was reported and the resolution. The total is in `x-total-count`.

**Access:** A site administrator. Tokens need the `read` scope and access to all repositories.

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | no | `open` (default), `resolved` or `all`. |
| `per_page` | integer | no | Results per page (default 30, at most 100). |
| `page` | integer | no | Page number, starting at 1. |

```sh
curl "https://diffinery.com/api/v3/admin/reports" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a report

```http
GET /api/v3/admin/reports/{id}
```

Site administrators only.

**Access:** A site administrator. Tokens need the `read` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/admin/reports/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Resolve or reopen a report

```http
PATCH /api/v3/admin/reports/{id}
```

Site administrators only. Audited as `report.resolve` or `report.reopen`.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | yes | `resolved` or `open`. |
| `resolution` | string | no | What you did, for `resolved` (up to 2,000 characters). |

```sh
curl -X PATCH "https://diffinery.com/api/v3/admin/reports/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"state":"..."}'
```

### Get a repository's Actions suspension

```http
GET /api/v3/admin/repos/{owner}/{repo}/actions-suspension
```

Site administrators only. `suspended`, `reason`, `suspended_by`, `suspended_at`, and `owner_suspended` when its owner's Actions are suspended.

**Access:** A site administrator. Tokens need the `read` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/admin/repos/acme/website/actions-suspension" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Suspend Actions for a repository

```http
PUT /api/v3/admin/repos/{owner}/{repo}/actions-suspension
```

Site administrators only. No runs start, queued jobs fail and no sandboxes open; what runs now stops (`stopped`). Audited as `actions.suspend`.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `reason` | string | yes | Why (up to 500 characters). Shown to the people affected and kept in the audit log. |

```sh
curl -X PUT "https://diffinery.com/api/v3/admin/repos/acme/website/actions-suspension" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"reason":"..."}'
```

### Lift a repository's Actions suspension

```http
DELETE /api/v3/admin/repos/{owner}/{repo}/actions-suspension
```

Site administrators only. New work can start again; nothing restarts. Audited as `actions.unsuspend`.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/admin/repos/acme/website/actions-suspension" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List app

```http
GET /api/v3/app
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/app" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List installations

```http
GET /api/v3/app/installations
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/app/installations" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a installation

```http
GET /api/v3/app/installations/{id}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/app/installations/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a installation

```http
DELETE /api/v3/app/installations/{id}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/app/installations/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a access token

```http
POST /api/v3/app/installations/{id}/access_tokens
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X POST "https://diffinery.com/api/v3/app/installations/1/access_tokens" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Set suspended

```http
PUT /api/v3/app/installations/{id}/suspended
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X PUT "https://diffinery.com/api/v3/app/installations/1/suspended" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete suspended

```http
DELETE /api/v3/app/installations/{id}/suspended
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/app/installations/1/suspended" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a app

```http
GET /api/v3/apps/{slug}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `slug` | string | yes | slug |

```sh
curl "https://diffinery.com/api/v3/apps/slug" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List apps

```http
GET /api/v3/diffinery/apps
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/diffinery/apps" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a app

```http
POST /api/v3/diffinery/apps
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/apps" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a app (GET /diffinery/apps/slug)

```http
GET /api/v3/diffinery/apps/{slug}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `slug` | string | yes | slug |

```sh
curl "https://diffinery.com/api/v3/diffinery/apps/slug" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update a app

```http
PATCH /api/v3/diffinery/apps/{slug}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `slug` | string | yes | slug |

```sh
curl -X PATCH "https://diffinery.com/api/v3/diffinery/apps/slug" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a app

```http
DELETE /api/v3/diffinery/apps/{slug}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `slug` | string | yes | slug |

```sh
curl -X DELETE "https://diffinery.com/api/v3/diffinery/apps/slug" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a installation

```http
POST /api/v3/diffinery/apps/{slug}/installations
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `slug` | string | yes | slug |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/apps/slug/installations" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List keys

```http
GET /api/v3/diffinery/apps/{slug}/keys
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `slug` | string | yes | slug |

```sh
curl "https://diffinery.com/api/v3/diffinery/apps/slug/keys" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a key

```http
POST /api/v3/diffinery/apps/{slug}/keys
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `slug` | string | yes | slug |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/apps/slug/keys" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a key

```http
DELETE /api/v3/diffinery/apps/{slug}/keys/{keyId}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `slug` | string | yes | slug |
| `keyId` | string | yes | keyId |

```sh
curl -X DELETE "https://diffinery.com/api/v3/diffinery/apps/slug/keys/keyId" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Your auto-merge setting

```http
GET /api/v3/diffinery/auto-merge
```

Whether Diffinery turns on auto-merge for the pull requests you open: `{ enabled, merge_method }`, where `merge_method` is `default` (as the branch merges), `merge`, `squash`, `rebase`, or null when off. An agent's token reads the agent's own. See /docs/collaboration/merge-on-green.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope and access to all repositories.

```sh
curl "https://diffinery.com/api/v3/diffinery/auto-merge" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Turn auto-merge on or off for pull requests you open

```http
PUT /api/v3/diffinery/auto-merge
```

People only. When on, Diffinery turns on auto-merge for you as you open a pull request (or mark your draft ready), wherever its base branch has at least one required check; it merges once every rule of the branch is met, approvals included. The body may also be just `true` or `false`. Returns the setting. Audited as `account.auto_merge`. See /docs/collaboration/merge-on-green.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories.

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `enabled` | boolean | yes | On or off. |
| `merge_method` | string | no | `default` (as the branch merges, the default), `merge`, `squash` or `rebase`. |

```sh
curl -X PUT "https://diffinery.com/api/v3/diffinery/auto-merge" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled":true}'
```

### Your email address and whether it is suppressed

```http
GET /api/v3/diffinery/email
```

`suppressed` is null, or why Diffinery sends nothing to your address: `reason` (`hard-bounce`, `complaint` or `manual`), `detail`, `source`, `created_at` and `owner_can_lift`.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/diffinery/email" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Ask for the email that turns email back on

```http
POST /api/v3/diffinery/email/verification
```

When your address is suppressed by a bounce or complaint, sends one email to it, past the suppression list; following its link while signed in lifts the suppression. 409 when it isn't suppressed, 403 for a suppression a site administrator added, at most 3 an hour.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories.

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/email/verification" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get a installation (GET /diffinery/installations/id)

```http
GET /api/v3/diffinery/installations/{id}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/diffinery/installations/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Update a installation

```http
PATCH /api/v3/diffinery/installations/{id}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/diffinery/installations/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a installation (DELETE /diffinery/installations/id)

```http
DELETE /api/v3/diffinery/installations/{id}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/diffinery/installations/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Create a accept permission

```http
POST /api/v3/diffinery/installations/{id}/accept_permissions
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/installations/1/accept_permissions" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Set suspended (PUT /diffinery/installations/id/suspended)

```http
PUT /api/v3/diffinery/installations/{id}/suspended
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X PUT "https://diffinery.com/api/v3/diffinery/installations/1/suspended" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete suspended (DELETE /diffinery/installations/id/suspended)

```http
DELETE /api/v3/diffinery/installations/{id}/suspended
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/diffinery/installations/1/suspended" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List your model keys

```http
GET /api/v3/diffinery/model-keys
```

Your saved model API keys for agent tasks: `provider` (`anthropic`, `openai` or `openrouter`), `hint` (the key's last four characters), `opted_in_at`, `created_at` and `updated_at`. The keys themselves are never returned. See /docs/agents/tasks#model-access.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/diffinery/model-keys" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Save a model key

```http
PUT /api/v3/diffinery/model-keys/{provider}
```

From a browser session only: no token, agent, job or sandbox can set a model key. `provider` is `anthropic`, `openai` or `openrouter`. `accept_terms: true` records that you use that provider through Diffinery under your own account and its terms (422 without it). The key is encrypted, never shown again and never sent to a sandbox. Sends you a security email. Audited as `model_key.set`.

**Access:** Any active account (a token, or a browser session). No token can call it: it needs a browser session.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `provider` | string | yes | provider |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `key` | string | no | The API key (`sk-ant-...`, `sk-...` or `sk-or-...`). |
| `accept_terms` | boolean | no | Must be `true`. |

```sh
curl -X PUT "https://diffinery.com/api/v3/diffinery/model-keys/provider" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a model key

```http
DELETE /api/v3/diffinery/model-keys/{provider}
```

From a browser session only. Running tasks that use it lose model access. Audited as `model_key.delete`.

**Access:** Any active account (a token, or a browser session). No token can call it: it needs a browser session. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `provider` | string | yes | provider |

```sh
curl -X DELETE "https://diffinery.com/api/v3/diffinery/model-keys/provider" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get your model usage

```http
GET /api/v3/diffinery/model-usage
```

The model usage you paid for over the last `days`, as on Settings → Model access: `days`, `since`, and `repositories`, one line per repository (named as it was when its runs ended) and `kind` (`task`, `review` or `coordinator`) with `runs`, `reported_by_cli_runs`, `requests`, `input_tokens`, `output_tokens`, `cache_read_tokens`, `cache_write_tokens` and `cost_usd` (`null` when no run reported a cost). A token limited to some repositories sees only their lines. See /docs/agents/tasks#usage-and-cost.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `days` | integer | no | 1 to 90 (default 30). |

```sh
curl "https://diffinery.com/api/v3/diffinery/model-usage" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Report content to the site administrators

```http
POST /api/v3/diffinery/reports
```

Diffinery only. People only, at most 20 a day and one open report per thing. Returns the report (`id`, `kind`, `target`, `html_url`, `reason`, `body`, `state`, `created_at`). Audited as `report.create`.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories. **Success:** `201`.

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `kind` | string | yes | `user`, `repository`, `issue`, `pull_request` or `comment`. |
| `login` | string | no | The person, for `user`. |
| `repository` | string | no | `owner/name`, for everything but `user`. |
| `number` | integer | no | The issue or pull request, for `issue` and `pull_request`. |
| `comment_id` | string | no | The comment, for `comment`. |
| `reason` | string | yes | `spam`, `harassment`, `hate`, `violence`, `sexual`, `malware`, `impersonation` or `other`. |
| `body` | string | no | A note for the administrators (up to 2,000 characters; required for `other`). |

```sh
curl -X POST "https://diffinery.com/api/v3/diffinery/reports" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"kind":"...","reason":"..."}'
```

### List your agent tasks

```http
GET /api/v3/diffinery/tasks
```

Agent tasks you started across repositories where you still have write access, most recently changed first (for an agent's token: the tasks it runs). A token limited to repositories sees only those.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/diffinery/tasks" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Your morning view

```http
GET /api/v3/diffinery/today
```

Pull requests that need you, your agents' open pull requests with their state, and what merged, was released or failed in the last 24 hours, across the repositories you can see that were active in the last 30 days (at most 100). A token limited to repositories sees only those. See /docs/agents/today.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/diffinery/today" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List repositories

```http
GET /api/v3/installation/repositories
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/installation/repositories" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete token

```http
DELETE /api/v3/installation/token
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

```sh
curl -X DELETE "https://diffinery.com/api/v3/installation/token" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List the people an organization blocked

```http
GET /api/v3/orgs/{org}/blocks
```

Organization owners and site administrators.

**Access:** An owner of the organization (or a site admin). Tokens need the `read` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/blocks" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Check whether an organization blocked a person

```http
GET /api/v3/orgs/{org}/blocks/{username}
```

`204` if it did, `404` if not.

**Access:** An owner of the organization (or a site admin). Tokens need the `read` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `username` | string | yes | username |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/blocks/username" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Block a person from an organization

```http
PUT /api/v3/orgs/{org}/blocks/{username}
```

As blocking for yourself, for every repository the organization owns. Members can't be blocked. Audited as `org.block`.

**Access:** An owner of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `username` | string | yes | username |

```sh
curl -X PUT "https://diffinery.com/api/v3/orgs/acme/blocks/username" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Unblock a person from an organization

```http
DELETE /api/v3/orgs/{org}/blocks/{username}
```

Audited as `org.unblock`.

**Access:** An owner of the organization (or a site admin). Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `username` | string | yes | username |

```sh
curl -X DELETE "https://diffinery.com/api/v3/orgs/acme/blocks/username" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get an organization's agent policy

```http
GET /api/v3/orgs/{org}/diffinery/agent-policy
```

Owners only (and site administrators); a token limited to repositories gets 403. `keys` (`personal`, `either` or `organization`: whose key pays), `runtimes` (`claude-code`, `codex`, `custom`), `providers` (`anthropic`, `openai`, `openrouter`), `max_running` (tasks at once per repository, 1 to 10), `terminals`, `terminal_tasks`, `review`, `member_monthly_tokens` (`null` for no allowance), `updated_by` and `updated_at`. See /docs/agents/organizations.

**Access:** An owner of the organization (or a site admin). Tokens need the `read` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/diffinery/agent-policy" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Change an organization's agent policy

```http
PUT /api/v3/orgs/{org}/diffinery/agent-policy
```

From a browser session only, by an owner. Fields left out stay as they are; answers with the whole policy. 422 when a value is out of range, or no runtime or provider is left allowed. Each repository's tasks at once are held to `max_running` right away. Audited as `org.agent_policy.update`, with the new values.

**Access:** An owner of the organization (or a site admin). No token can call it: it needs a browser session.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `keys` | string | no | `personal` (each person's own keys), `either` (the organization's keys when it has them) or `organization` (only the organization's keys). |
| `runtimes` | array | no | Allowed runtimes: `claude-code`, `codex`, `custom`. At least one. |
| `providers` | array | no | Allowed providers: `anthropic`, `openai`, `openrouter`. At least one. |
| `max_running` | integer | no | Most tasks at once per repository, 1 to 10. |
| `terminals` | boolean | no | Allow web terminals. |
| `terminal_tasks` | boolean | no | Let terminals run agent tasks. |
| `review` | boolean | no | Allow agent review. |
| `member_monthly_tokens` | integer | no | Tokens one person may spend of the organization's keys in a calendar month (UTC), 10,000 to 10,000,000,000, or `null` for no allowance. |

```sh
curl -X PUT "https://diffinery.com/api/v3/orgs/acme/diffinery/agent-policy" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List an organization's model keys

```http
GET /api/v3/orgs/{org}/diffinery/model-keys
```

Owners only; a token limited to repositories gets 403. Each key as `GET /diffinery/model-keys` shows a personal one: `provider`, `hint` (last four characters), `opted_in_at`, `created_at` and `updated_at`. The keys themselves are never returned. See /docs/agents/organizations.

**Access:** An owner of the organization (or a site admin). Tokens need the `read` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/diffinery/model-keys" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Save an organization's model key

```http
PUT /api/v3/orgs/{org}/diffinery/model-keys/{provider}
```

From a browser session with a sign-in from the last 2 hours, by an owner. `provider` is `anthropic`, `openai` or `openrouter`; `accept_terms: true` is required. The key is encrypted, never shown again and never sent to a sandbox. Every owner gets a security email. Audited as `org.model_key.set`.

**Access:** An owner of the organization (or a site admin). No token can call it: it needs a browser session.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `provider` | string | yes | provider |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `key` | string | no | The API key (`sk-ant-...`, `sk-...` or `sk-or-...`). |
| `accept_terms` | boolean | no | Must be `true`. |

```sh
curl -X PUT "https://diffinery.com/api/v3/orgs/acme/diffinery/model-keys/provider" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete an organization's model key

```http
DELETE /api/v3/orgs/{org}/diffinery/model-keys/{provider}
```

From a browser session with a sign-in from the last 2 hours, by an owner. 404 when the organization has no key for that provider. Audited as `org.model_key.delete`.

**Access:** An owner of the organization (or a site admin). No token can call it: it needs a browser session. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |
| `provider` | string | yes | provider |

```sh
curl -X DELETE "https://diffinery.com/api/v3/orgs/acme/diffinery/model-keys/provider" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get an organization's model usage

```http
GET /api/v3/orgs/{org}/diffinery/model-usage
```

Owners only; a token limited to repositories gets 403. The runs the organization's keys paid for over the last `days`, shaped like `GET /diffinery/model-usage` with a `person` on each line, and `month`: `month`, `member_monthly_tokens` and `people` (each `person` and their `tokens` on the organization's keys this month). See /docs/agents/organizations#usage.

**Access:** An owner of the organization (or a site admin). Tokens need the `read` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `days` | integer | no | 1 to 90 (default 30). |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/diffinery/model-usage" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List installation

```http
GET /api/v3/orgs/{org}/installation
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/installation" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get an organization's quotas and usage

```http
GET /api/v3/orgs/{org}/usage
```

The same as `GET /user/usage`, for the organization's owners and admins.

**Access:** An owner or admin of the organization (or a site admin). Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

```sh
curl "https://diffinery.com/api/v3/orgs/acme/usage" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get agent review settings

```http
GET /api/v3/repos/{owner}/{repo}/diffinery/agent-review
```

Whether agent review is on, which agent reviews with which runtime, whose model key every review uses (`uses_key_of`), when it reviews (`trigger`: `push`, `open` or `request`), which pull requests (`authors`: `all`, `people` or `agents`), `drafts`, `autofix`, `daily_limit` and `tokens_per_review`. `{"enabled": false}` when it was never turned on. Needs write access. See /docs/agents/review.

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/diffinery/agent-review" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Turn agent review on, change or off

```http
PUT /api/v3/repos/{owner}/{repo}/diffinery/agent-review
```

From a browser session only, by a repository admin who can run tasks as the agent and has the runtime's model key: every review on the repository, including ones other people ask for, spends that admin's key, so `accept_terms` must be true. `{"enabled": false}` turns it off. Audited as `review.settings`.

**Access:** Admin access to the repository (or to the package). No token can call it: it needs a browser session.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `agent` | string | no | The reviewing agent's login (required). |
| `runtime` | string | no | `claude-code` (default), `codex` or `custom`. |
| `provider` | string | no | Where the runtime's model calls go: its own provider (`anthropic` for Claude Code, `openai` for Codex; the default) or `openrouter`. |
| `model` | string | no | With `provider: openrouter`: the OpenRouter model id (default `~anthropic/claude-sonnet-latest` for Claude Code, `~openai/gpt-sol-latest` for Codex). |
| `command` | string | no | For `custom`: the shell command; it must end its output with the findings block the prompt describes. |
| `trigger` | string | no | `push` (default: on open and every push), `open` (once per pull request) or `request` (only when asked). |
| `authors` | string | no | `all` (default), `people` or `agents`. |
| `drafts` | boolean | no | Review drafts too (default false). |
| `autofix` | boolean | no | Start a fix task on the pull request's branch for blocking findings (default false; at most 3 times per pull request). |
| `daily_limit` | integer | no | Most reviews and autofix runs the repository starts in 24 hours, 1 to 1000 (default 50). Past it, pull requests get an action-required check, autofix waits, and you get an email. |
| `tokens_per_review` | integer | no | Most tokens one review may use, counted from the provider's responses (cache reads count as a tenth), 100000 to 50000000 (default 2000000). |
| `accept_terms` | boolean | no | Must be true: reviews use your model key. |
| `enabled` | boolean | no | `false` turns agent review off. |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/diffinery/agent-review" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get the agent setup check

```http
GET /api/v3/repos/{owner}/{repo}/diffinery/agent-setup
```

The latest Check on Settings → Agent setup, or `check: null` before any: `ok`, `checked_at`, `first_ok_at` (when a check first passed), the `account` and `token` (`name`, `prefix`) that reported it, `cli_version` and the `checks` lines. See [Cloud agent environments](https://diffinery.com/docs/connect/cloud-agents).

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/diffinery/agent-setup" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Report an agent setup check

```http
POST /api/v3/repos/{owner}/{repo}/diffinery/agent-setup/checks
```

What the hosted setup script (`/{owner}/{repo}/agent-setup.sh`, run by `diffinery setup --repo`) sends after its self-test: the Check on Settings → Agent setup. Tokens only, with write access to the repository; browser sessions and workflow tokens get 403. The report is green only when every line passed. Returns `ok` and the page's `html_url`. See [Cloud agent environments](https://diffinery.com/docs/connect/cloud-agents).

**Access:** Write access to the repository. Tokens need the `write` scope. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `checks` | object[] | yes | 1 to 30 lines of `{ name, ok, message }`: what was checked, whether it passed, and what to change when it didn't. |
| `cli_version` | string | no | The CLI's version. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/diffinery/agent-setup/checks" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"checks":"..."}'
```

### Hide (minimize) a comment

```http
PUT /api/v3/repos/{owner}/{repo}/diffinery/comments/{id}/minimized
```

Diffinery only (GitHub's GraphQL `minimizeComment`). Write access, people only. The comment is shown collapsed with its reason. Audited as `comment.minimize`.

**Access:** Write access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `reason` | string | yes | `spam`, `abuse`, `off_topic`, `outdated`, `duplicate` or `resolved` (or GitHub's `classifier`, such as `OFF_TOPIC`). |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/diffinery/comments/1/minimized" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"reason":"..."}'
```

### Show a hidden comment again

```http
DELETE /api/v3/repos/{owner}/{repo}/diffinery/comments/{id}/minimized
```

Diffinery only. Write access, people only. Audited as `comment.unminimize`.

**Access:** Write access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/diffinery/comments/1/minimized" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete closed pull requests

```http
POST /api/v3/repos/{owner}/{repo}/diffinery/delete-closed-pulls
```

For starting over with fresh history after rewriting the branches. Permanently deletes every closed and merged pull request (not ones still in the merge queue) with its comments, reviews, review comments, timeline events, reactions and `refs/pull/{number}/*` refs, then purges unreachable objects as `POST .../diffinery/purge-unreachable` does. Issues, open pull requests, branches, tags and workflow runs stay; pull request numbers are not reused. Returns `{ pull_requests, objects, bytes }`. People only, not agents. Repositories of up to 300,000 objects (422 otherwise). From a browser session whose sign-in is more than 2 hours old: 403 `Confirm it's you: sign in with your passkey again to do this.` with a `confirm` URL. Audited as `repo.delete_closed_pulls`. See /docs/repositories/overview#start-over-with-fresh-history.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/diffinery/delete-closed-pulls" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get the project

```http
GET /api/v3/repos/{owner}/{repo}/diffinery/project
```

The repository's project: `settings` (`max_running`, `instructions`, `plan_first`), `memory` (`body`, `version`, `updated_by`, `updated_at`) and `board`, the agent tasks by column (`waiting`, `working`, `queued`, `review`, `landing`, `done`, `idle`). Agent reviews aren't on the board. Needs write access. See /docs/agents/projects.

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/diffinery/project" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get your coordinator

```http
GET /api/v3/repos/{owner}/{repo}/diffinery/project/coordinator
```

Your coordinator's settings in this project: `enabled`, `agent`, `runtime`, `command`, `provider`, `model`, `tokens_per_run`, `tokens_per_task`, `opted_in_at`, `updated_at`. Needs write access.

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/diffinery/project/coordinator" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Turn on or change your coordinator

```http
PUT /api/v3/repos/{owner}/{repo}/diffinery/project/coordinator
```

Your agent then reads your posts and turns them into tasks, on your model key. Each coordinator starts at most 5 tasks per post and 20 per 24 hours in the project. A person in a browser session only. Audited as `project.coordinator`. See /docs/agents/projects#coordinator.

**Access:** Write access to the repository. No token can call it: it needs a browser session.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `agent` | string | yes | The login of an agent you manage with write access to the repository. |
| `runtime` | string | no | `claude-code` (default), `codex` or `custom`. |
| `command` | string | no | For `custom`: the shell command. |
| `provider` | string | no | `openrouter` to run Claude Code or Codex via OpenRouter. |
| `model` | string | no | With `provider: openrouter`: the OpenRouter model id. |
| `tokens_per_run` | integer | no | Token budget of each coordinator run, 100,000 to 50,000,000 (default 1,000,000). |
| `tokens_per_task` | integer | no | Token budget of each run of a task it starts, 100,000 to 50,000,000 (default 2,000,000). |
| `accept` | boolean | yes | Must be `true`: confirms your coordinator and its tasks use your model key. |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/diffinery/project/coordinator" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"agent":"...","accept":true}'
```

### Turn off your coordinator

```http
DELETE /api/v3/repos/{owner}/{repo}/diffinery/project/coordinator
```

A person in a browser session only. Audited as `project.coordinator`.

**Access:** Write access to the repository. No token can call it: it needs a browser session.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/repos/acme/website/diffinery/project/coordinator" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List the coordinators in a project

```http
GET /api/v3/repos/{owner}/{repo}/diffinery/project/coordinators
```

Every person's coordinator in this project, oldest first: `person`, `agent`, `runtime`, `provider`, `model`, `opted_in_at`. Never their token budgets or custom command. Needs write access. See /docs/agents/projects#coordinator.

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/diffinery/project/coordinators" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get the project memory

```http
GET /api/v3/repos/{owner}/{repo}/diffinery/project/memory
```

The current memory and its last 50 `versions` (`version`, `updated_by`, `updated_at`, `length`). Every agent task reads it as background notes; agent reviews don't. Needs write access.

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/diffinery/project/memory" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Save or restore the project memory

```http
PUT /api/v3/repos/{owner}/{repo}/diffinery/project/memory
```

Saves `body` (at most 40,000 characters) as a new version, or restores an earlier version as a new one with `restore` (404 `no such memory version`). A person in a browser session only. Audited as `project.memory`.

**Access:** Write access to the repository. No token can call it: it needs a browser session.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `body` | string | no | The new memory (Markdown). |
| `restore` | integer | no | A version number to restore instead. |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/diffinery/project/memory" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List the project conversation

```http
GET /api/v3/repos/{owner}/{repo}/diffinery/project/posts
```

Posts and task events, oldest first: those after `after`, or the latest 100. Needs write access.

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `after` | integer | no | Return posts after this id (default 0). |
| `per_page` | integer | no | At most 100 (default 100). |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/diffinery/project/posts" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Post to the project conversation

```http
POST /api/v3/repos/{owner}/{repo}/diffinery/project/posts
```

Markdown, at most 20,000 characters (422 otherwise). If you have a coordinator in this project, it handles the post unless you send `coordinator: false`; the response's `coordinator` says whether it did. A person in a browser session only. 403 on an archived repository.

**Access:** Write access to the repository. No token can call it: it needs a browser session. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `body` | string | yes | The post. |
| `coordinator` | boolean | no | `false` to post without handing it to your coordinator. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/diffinery/project/posts" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"body":"..."}'
```

### Hand a post to your coordinator

```http
POST /api/v3/repos/{owner}/{repo}/diffinery/project/posts/{n}/handle
```

Your coordinator handles post `n`, anyone's, on your model key. Each post is handled once. A person in a browser session only. Audited as `project.coordinate`. See /docs/agents/projects#coordinator.

**Access:** Write access to the repository. No token can call it: it needs a browser session.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `n` | string | yes | n |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/diffinery/project/posts/n/handle" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Change the project settings

```http
PUT /api/v3/repos/{owner}/{repo}/diffinery/project/settings
```

Project instructions every agent task and agent review gets, how many tasks run at once, and whether tasks plan first. Tasks beyond `max_running` queue and start oldest first. A person in a browser session only. Audited as `project.settings`.

**Access:** Admin access to the repository (or to the package). No token can call it: it needs a browser session.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `max_running` | integer | no | 1 to 10 (default 3). |
| `instructions` | string | no | At most 10,000 characters. |
| `plan_first` | string | no | `off` (default: tasks build at once unless started with `plan_first: true`), `default` (tasks plan first unless started with `plan_first: false`) or `required` (every task plans first, including ones coordinators start). |

```sh
curl -X PUT "https://diffinery.com/api/v3/repos/acme/website/diffinery/project/settings" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Purge unreachable objects

```http
POST /api/v3/repos/{owner}/{repo}/diffinery/purge-unreachable
```

Permanently deletes every commit, tree and file that no branch, tag, pull request, merge queue entry or unfinished workflow run reaches, and empties the archive cache, so a secret force-pushed away can't be fetched by its SHA. Returns `{ objects, bytes }`. People only, not agents. Repositories of up to 300,000 objects (422 otherwise). From a browser session whose sign-in is more than 2 hours old: 403 `Confirm it's you: sign in with your passkey again to do this.` with a `confirm` URL. Audited as `repo.purge_unreachable`. See /docs/security/push-protection#removing-a-secret-that-was-pushed.

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/diffinery/purge-unreachable" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List agent tasks

```http
GET /api/v3/repos/{owner}/{repo}/diffinery/tasks
```

The repository's agent tasks, newest first. Needs write access: transcripts show an agent's reasoning and command output. `state` filters: `queued`, `running`, `ready`, `failed` or `stopped`, or `active` for running and queued together.

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | no | `queued`, `running`, `ready`, `failed`, `stopped` or `active` (running or queued). |
| `per_page` | integer | no | At most 100 (default 50). |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/diffinery/tasks" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Start an agent task

```http
POST /api/v3/repos/{owner}/{repo}/diffinery/tasks
```

From a browser session only, by a person with write access, as one of their agents (they own it, or administer the organization that owns it) that has write access here: each run spends the person's own model key, so no token can start one. The agent works in a sandbox, then Diffinery pushes `agent/<number>-<slug>` and opens a pull request as the agent. 422 when the runtime needs a model key you haven't saved. Audited as `task.start`. See /docs/agents/tasks.

**Access:** Write access to the repository. No token can call it: it needs a browser session. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `goal` | string | no | What to do (required, at most 20,000 characters). |
| `runtime` | string | no | `claude-code` (default), `codex` or `custom`. |
| `provider` | string | no | Where the runtime's model calls go: its own provider (`anthropic` for Claude Code, `openai` for Codex; the default) or `openrouter`. |
| `model` | string | no | With `provider: openrouter`: the OpenRouter model id (default `~anthropic/claude-sonnet-latest` for Claude Code, `~openai/gpt-sol-latest` for Codex). |
| `agent` | string | no | The agent's login (required). |
| `base` | string | no | Branch to start from (default: the default branch). |
| `plan_first` | boolean | no | `true` to plan in a read-only sandbox before building, `false` to build at once. Left out, the project's default; a project that requires plans ignores `false`. See /docs/agents/tasks#plan-first. |
| `attempts` | integer | no | 1 (default) to 4: run the first build as that many attempts side by side, then pick one (422 above 1 for a task on a pull request's branch). See /docs/agents/tasks#best-of-n. |
| `fix_checks` | boolean | no | Start a fix run when the pull request's checks fail (default `true`, `false` for a task on a pull request's branch). See /docs/agents/tasks#verify-and-land. |
| `land` | boolean | no | Turn on auto-merge for its pull request as the task's agent, so it merges once approved and checks pass (default `false`). |
| `command` | string | no | For `custom`: the shell command to run. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/diffinery/tasks" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get an agent task

```http
GET /api/v3/repos/{owner}/{repo}/diffinery/tasks/{number}
```

The task, its runs and its pull request. Needs write access. A plan-first task also has `plan_state` (`planning`, `waiting`, `approved` or `split`) and `plan`; a task split from a plan has `parent_task`. A task with more than one attempt has `pick_state` (`running`, `waiting` or `picked`) and `picked_attempt`, and each run its `attempt`. Every task has `fix_checks`, `check_fixes` (fix runs started so far) and `land`, `paid_by` (`person`, or `organization` when an organization's key pays), and `usage` (the model usage of all its runs; each run has its own `usage`, with `source`: `proxy`, or `runtime` for a run in a terminal). See /docs/agents/tasks#usage-and-cost.

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/diffinery/tasks/42" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Change a task's options

```http
PATCH /api/v3/repos/{owner}/{repo}/diffinery/tasks/{number}
```

From a browser session only, by the person who started the task. `fix_checks` starts a fix run when its pull request's checks fail (one per commit, at most 3 per task); turning `land` on turns on auto-merge for an open pull request as the task's agent, under the usual rules for agents. 422 when a value isn't `true` or `false`; 409 `only agent tasks have these options` for an agent review. Audited as `task.options`. See /docs/agents/tasks#verify-and-land.

**Access:** Write access to the repository. No token can call it: it needs a browser session.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `fix_checks` | boolean | no | Fix failing checks. |
| `land` | boolean | no | Land when approved. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/repos/acme/website/diffinery/tasks/42" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Compare a task's attempts

```http
GET /api/v3/repos/{owner}/{repo}/diffinery/tasks/{number}/attempts
```

Needs write access. One entry per attempt of a best-of-N task: `attempt`, `run`, `state`, `error`, `branch`, `head_sha`, `changes` (`files`, `additions`, `deletions`), `checks` and `failing_checks` on its branch, `model_requests`, `tokens`, `summary` (its last message) and `compare_url`. See /docs/agents/tasks#best-of-n.

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/diffinery/tasks/42/attempts" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Pick a task's attempt

```http
POST /api/v3/repos/{owner}/{repo}/diffinery/tasks/{number}/attempts/{attempt}/pick
```

From a browser session only, by the person who started the task. The attempt's branch becomes the task's branch, with a pull request; the other attempts' branches are deleted. 409 `the attempts are still running`, `attempt <n> is already picked` or `this task has no attempts to pick from`; 404 `no such attempt`; 422 `attempt <n> has no work to pick: ...` when it changed nothing or didn't finish. Audited as `task.pick`.

**Access:** Write access to the repository. No token can call it: it needs a browser session. **Success:** `202`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |
| `attempt` | string | yes | attempt |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/diffinery/tasks/42/attempts/attempt/pick" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Send a task a follow-up

```http
POST /api/v3/repos/{owner}/{repo}/diffinery/tasks/{number}/messages
```

From a browser session only, by the person who started the task. Starts a new run on the task's branch with the message (while a run is active, it waits and starts when that run ends). Audited as `task.message`.

**Access:** Write access to the repository. No token can call it: it needs a browser session. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `body` | string | no | The message. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/diffinery/tasks/42/messages" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Approve a task's plan

```http
POST /api/v3/repos/{owner}/{repo}/diffinery/tasks/{number}/plan/approve
```

From a browser session only, by the person who started the task. The build run starts with the goal and the plan, and every later run gets the plan as the approved one. 409 `the plan isn't ready yet` while it plans, `this task has no plan waiting for approval`, or `the task is running`. Audited as `task.plan_approve`. See /docs/agents/tasks#plan-first.

**Access:** Write access to the repository. No token can call it: it needs a browser session. **Success:** `202`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/diffinery/tasks/42/plan/approve" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Split a task's plan into tasks

```http
POST /api/v3/repos/{owner}/{repo}/diffinery/tasks/{number}/plan/split
```

From a browser session only, by the person who started the task. Your coordinator gets the goal and the plan as a post of yours and starts tasks for its parts, each with `parent_task`; this task is then done with. Returns `post`, `task` (the coordinator's run) and `status` (`started` or `queued`). 422 `set up your coordinator for this project first` without a coordinator; the same 409s as approving. Audited as `task.plan_split`.

**Access:** Write access to the repository. No token can call it: it needs a browser session. **Success:** `202`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/diffinery/tasks/42/plan/split" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Retry a task

```http
POST /api/v3/repos/{owner}/{repo}/diffinery/tasks/{number}/retry
```

From a browser session only, by the person who started the task, when no run is active (409 otherwise). Audited as `task.retry`.

**Access:** Write access to the repository. No token can call it: it needs a browser session. **Success:** `201`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/diffinery/tasks/42/retry" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Stop a task

```http
POST /api/v3/repos/{owner}/{repo}/diffinery/tasks/{number}/stop
```

The person who started it, its agent, or a repository admin. Stops the agent, closes the sandbox (its git credential stops working) and ends the run's model access. Work already pushed stays. Audited as `task.stop`.

**Access:** Write access to the repository. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/diffinery/tasks/42/stop" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Read a task's transcript

```http
GET /api/v3/repos/{owner}/{repo}/diffinery/tasks/{number}/transcript
```

Lines after `after` (a line number), oldest first: `stream` is `out` and `err` (the runtime's output, Claude Code's `stream-json` or Codex's `--json` lines), `setup` (installing and pushing) or `note` (Diffinery's own). Model keys and git credentials are masked.

**Access:** Write access to the repository. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |
| `number` | string | yes | Issue or pull request number. |

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `after` | integer | no | Return lines after this one. |
| `per_page` | integer | no | At most 5000 (default 2000). |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/diffinery/tasks/42/transcript" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List installation (GET /repos/owner/repo/installation)

```http
GET /api/v3/repos/{owner}/{repo}/installation
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

```sh
curl "https://diffinery.com/api/v3/repos/acme/website/installation" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Transfer a repository

```http
POST /api/v3/repos/{owner}/{repo}/transfer
```

Moves the repository to `new_owner`: the caller's own account, or an organization where the caller is an owner or admin. Needs admin access to the repository (a personal repository: its owner) and a token with the admin scope; agents, job tokens (`GITHUB_TOKEN`) and sandbox tokens are refused. 422 when the new owner already has a repository (or a container image of a moved image's name) with that name. Git data, issues, pull requests, Actions runs, secrets, variables, environments, webhooks and caches move with it, and so do container images linked to it. Direct collaborators keep their access; grants that came from the old organization (its members, their agents, its agents) are dropped, and the new owner's organization secrets and variables apply. The old owner/name keeps working for anyone who can read the repository, as on GitHub: API calls get a 301 (reads) or 307 (anything else) to the new URL, web pages a 301, Git (with a `This repository moved` notice on push) and MCP are served under the old name, and image names resolve to the moved images. Creating a repository at the old name ends the redirect. Admins of both owners get an email. Audited as `repo.transfer`. Returns the repository. From a browser session whose sign-in is more than 2 hours old: 403 `Confirm it's you: sign in with your passkey again to do this.` with a `confirm` URL (see /docs/security/overview#confirming-its-you).

**Access:** Admin access to the repository (or to the package). Tokens need the `admin` scope and access to all repositories. **Success:** `202`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `owner` | string | yes | Account (user or organization) that owns the repository or package. |
| `repo` | string | yes | Repository name. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `new_owner` | string | yes | Login of the user or organization to transfer to. |
| `new_name` | string | no | A new name for the repository (default: keep its name). |

```sh
curl -X POST "https://diffinery.com/api/v3/repos/acme/website/transfer" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"new_owner":"..."}'
```

### List the people you blocked

```http
GET /api/v3/user/blocks
```

People only. See [Blocking and reporting](https://diffinery.com/docs/accounts/blocking-and-reporting).

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope and access to all repositories.

```sh
curl "https://diffinery.com/api/v3/user/blocks" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Check whether you blocked a person

```http
GET /api/v3/user/blocks/{username}
```

`204` if you did, `404` if not.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `username` | string | yes | username |

```sh
curl "https://diffinery.com/api/v3/user/blocks/username" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Block a person

```http
PUT /api/v3/user/blocks/{username}
```

In your repositories they (and their agents) can't open issues or pull requests, comment, review or react; they stop being a collaborator, pending invitations between you are cancelled and you get no notifications from them. Audited as `user.block`.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `username` | string | yes | username |

```sh
curl -X PUT "https://diffinery.com/api/v3/user/blocks/username" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Unblock a person

```http
DELETE /api/v3/user/blocks/{username}
```

Audited as `user.unblock`.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `username` | string | yes | username |

```sh
curl -X DELETE "https://diffinery.com/api/v3/user/blocks/username" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List installations (GET /user/installations)

```http
GET /api/v3/user/installations
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/user/installations" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List repositories (GET /user/installations/id/repositories)

```http
GET /api/v3/user/installations/{id}/repositories
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl "https://diffinery.com/api/v3/user/installations/1/repositories" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Set a repository

```http
PUT /api/v3/user/installations/{id}/repositories/{repoId}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |
| `repoId` | string | yes | repoId |

```sh
curl -X PUT "https://diffinery.com/api/v3/user/installations/1/repositories/repoId" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Delete a repository (DELETE /user/installations/id/repositories/repoId)

```http
DELETE /api/v3/user/installations/{id}/repositories/{repoId}
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `write` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |
| `repoId` | string | yes | repoId |

```sh
curl -X DELETE "https://diffinery.com/api/v3/user/installations/1/repositories/repoId" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List your organization memberships

```http
GET /api/v3/user/memberships/orgs
```

Active memberships and pending invitations, each with `state` (`active` or `pending`), `role` (GitHub's `admin` or `member`) and `diffinery_role` (`owner`, `admin` or `member`).

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope and access to all repositories.

Query parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | no | `active` or `pending`. |

```sh
curl "https://diffinery.com/api/v3/user/memberships/orgs" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get your organization membership

```http
GET /api/v3/user/memberships/orgs/{org}
```

404 when you are neither a member nor invited.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

```sh
curl "https://diffinery.com/api/v3/user/memberships/orgs/acme" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Accept an organization invitation

```http
PATCH /api/v3/user/memberships/orgs/{org}
```

Send `{"state": "active"}` to join with the role the invitation offers. Audited as `invite.accept`.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `org` | string | yes | Organization login. |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | string | yes | `active`. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/user/memberships/orgs/acme" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"state":"..."}'
```

### List your repository invitations

```http
GET /api/v3/user/repository_invitations
```

Pending invitations to repositories, sent to your username or your email address.

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope and access to all repositories.

```sh
curl "https://diffinery.com/api/v3/user/repository_invitations" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Accept a repository invitation

```http
PATCH /api/v3/user/repository_invitations/{id}
```

You get the role it offers. Audited as `invite.accept`.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X PATCH "https://diffinery.com/api/v3/user/repository_invitations/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Decline a repository invitation

```http
DELETE /api/v3/user/repository_invitations/{id}
```

The invitation is deleted; nobody is told. Audited as `invite.decline`.

**Access:** Any active account (a token, or a browser session). Tokens need the `write` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Identifier. |

```sh
curl -X DELETE "https://diffinery.com/api/v3/user/repository_invitations/1" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Get your quotas and usage

```http
GET /api/v3/user/usage
```

Hosted minutes used this month, hosted jobs running, sandboxes open, repositories owned and bytes stored, each with its `limit` (`-1` is unlimited), and `exempt` for accounts run by a site administrator. An agent gets its owner's. See [Limits](https://diffinery.com/docs/reference/limits#account-quotas).

**Access:** Any active account (a token, or a browser session). Tokens need the `read` scope.

```sh
curl "https://diffinery.com/api/v3/user/usage" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### List installation (GET /users/username/installation)

```http
GET /api/v3/users/{username}/installation
```

**Access:** Read access to the repository. Public repositories allow anyone to read. Tokens need the `read` scope.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `username` | string | yes | username |

```sh
curl "https://diffinery.com/api/v3/users/username/installation" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

### Suspend a person

```http
PUT /api/v3/users/{username}/suspended
```

Site administrators only (GitHub Enterprise's endpoint). Their sessions end, their tokens, agents and runners are refused, Actions in their repositories stop, and their profile, repositories and conversations are hidden from everyone else until they are unsuspended. Audited as `user.suspend`.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `username` | string | yes | username |

Body (JSON):

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `reason` | string | yes | Why (up to 500 characters). Emailed to them and kept in the audit log. |

```sh
curl -X PUT "https://diffinery.com/api/v3/users/username/suspended" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"reason":"..."}'
```

### Unsuspend a person

```http
DELETE /api/v3/users/{username}/suspended
```

Site administrators only. Everything comes back, tokens included. Audited as `user.unsuspend`.

**Access:** A site administrator. Tokens need the `admin` scope and access to all repositories. **Success:** `204`.

Path parameters:

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `username` | string | yes | username |

```sh
curl -X DELETE "https://diffinery.com/api/v3/users/username/suspended" \
  -H "Authorization: Bearer $DIFFINERY_TOKEN"
```

## Other HTTP endpoints

These aren't part of the JSON API, but clients and tools talk to them directly.

| Endpoint | What it is |
| --- | --- |
| `GET /{owner}/{repo}.git/info/refs` | Git smart HTTP: ref advertisement (`git clone`, `git fetch`, `git push`). Authenticate with a token as the password. See [Git](https://diffinery.com/docs/repositories/git). |
| `POST /{owner}/{repo}.git/git-upload-pack` | Git smart HTTP: fetch and clone. |
| `POST /{owner}/{repo}.git/git-receive-pack` | Git smart HTTP: push. |
| `POST /{owner}/{repo}.git/info/lfs/objects/batch` | Git LFS batch API. See [Git LFS](https://diffinery.com/docs/repositories/git-lfs). |
| `GET, PUT /{owner}/{repo}.git/info/lfs/objects/{oid}` | Git LFS object download and upload. |
| `GET /{owner}/{repo}/actions/runs/{run_id}/artifacts/{name}` | Download a workflow artifact by name or numeric id, for browsers (the run page links here). Serves a zip, the file itself for an artifact uploaded as a single unzipped file, or a `.tar.gz` for an artifact from an older runner. Expired artifacts aren't served. |
| `GET /{owner}/{repo}/agent-setup.sh` | The setup script for a cloud agent environment, from Settings → Agent setup: `curl -fsSL https://diffinery.com/{owner}/{repo}/agent-setup.sh | bash` installs the CLI, wires git and gh to `DIFFINERY_TOKEN`, clones the repository and checks it all. The same script for anyone, with no secret in it. See [Cloud agent environments](https://diffinery.com/docs/connect/cloud-agents). |
| `POST /mcp` | The MCP server (Streamable HTTP, JSON-RPC). See [MCP](https://diffinery.com/docs/agents/mcp) and the [MCP tool reference](https://diffinery.com/docs/reference/mcp-tools). |
| `GET /.well-known/oauth-protected-resource/mcp` | OAuth protected resource metadata for the MCP server (RFC 9728); also at `/.well-known/oauth-protected-resource`. See [How sign-in works](https://diffinery.com/docs/connect/how-sign-in-works). |
| `GET /.well-known/oauth-authorization-server` | OAuth authorization server metadata (RFC 8414) for MCP clients' browser sign-in. |
| `POST /oauth/register` | Dynamic client registration for MCP clients (RFC 7591): public clients, or confidential ones with `client_secret_basic` or `client_secret_post`. |
| `GET, POST /oauth/authorize` | The consent page where a person connects an MCP client, choosing whom it acts as and its access. Authorization code with PKCE (S256) only. |
| `POST /oauth/token` | Trades an authorization code (with its PKCE verifier) or a refresh token for an 8-hour access token and a new refresh token. |
| `POST /oauth/revoke` | Revokes a connected app's access or refresh token, ending its connection (RFC 7009). |
| `/v2/...` | The OCI container registry (Docker Registry HTTP API v2). See [Container registry](https://diffinery.com/docs/packages/container-registry). |
| `GET /.well-known/openid-configuration` | OIDC discovery for workflow ID tokens. See [OIDC](https://diffinery.com/docs/actions/oidc). |
| `GET /.well-known/jwks` | Public keys that sign workflow ID tokens. |
| `GET /.well-known/security.txt` | Where to report a vulnerability (RFC 9116): this instance's report form first, then any `SECURITY_CONTACT` entries. See [Reporting a vulnerability](https://diffinery.com/docs/security/disclosure). |
| `GET /.well-known/mcp-registry-auth` | The proof record that lets this instance's MCP server be published to the official MCP registry under its domain; 404 until `MCP_REGISTRY_AUTH` is set. See [MCP](https://diffinery.com/docs/agents/mcp#list-your-instance-in-the-mcp-registry). |
| `GET, POST /security/report` | The private security report form: signed in, or anonymously after Cloudflare Turnstile. Only site administrators can read reports. See [Reporting a vulnerability](https://diffinery.com/docs/security/disclosure). |
| `POST /-/email/events` | Signed bounce and complaint intake for the email suppression list; 404 until `MAIL_EVENTS_SECRET` is set. See [Site administration](https://diffinery.com/docs/admin/site-administration#bounces-complaints-and-the-suppression-list). |
| `GET, POST /-/unsubscribe/{token}` | One-click unsubscribe from a notification email (RFC 8058): a POST with `List-Unsubscribe=One-Click` turns that kind of email off. See [Notifications](https://diffinery.com/docs/accounts/notifications). |
| `GET /status` | The status page: each component's status and the incidents site administrators posted, for anyone without signing in. As JSON at `GET /api/v3/diffinery/status`. See [Status page](https://diffinery.com/docs/self-hosting/status-page). |
| `GET /healthz` | Health check: `{"ok": true}`. Point an external uptime monitor at it: the status page can't report the whole Worker being down. |
| `GET /llms.txt` | Index of these docs for AI agents. See [Docs for AI agents](https://diffinery.com/docs/agents/docs-for-agents). |
| `GET /llms-full.txt` | All of these docs in one Markdown file. |
| `GET /docs/{page}.md` | Any docs page as Markdown. |
| `GET /docs/api/openapi.json` | This reference as an OpenAPI 3.1 document. |
