> ## Documentation Index
> Fetch the complete documentation index at: https://docs.patch.gg/llms.txt
> Use this file to discover all available pages before exploring further.

# API overview

> Base URL, authentication, errors and conventions of the Patch API.

The Patch API is the public HTTP API behind patch.gg, the desktop app and `pch`. Anything they can do, your own tools and agents can do too.

## Base URL

```
https://patch.gg/api/v1
```

The API will move to `https://api.patch.gg/v1` (coming soon). Paths stay the same, and `patch.gg/api/v1` keeps working.

The API is described by an OpenAPI 3.1 document at `https://patch.gg/api/v1/openapi.json`. It's generated from the API's code, and the endpoint pages in this reference are built from it, so they always match what's deployed.

## Authentication

Public data, such as projects and their published releases, needs no authentication. Everything else does:

| Who | How |
| - | - |
| patch.gg | The session cookie from signing in with Discord or GitHub |
| People using `pch` | `pch login` shows a code that you approve on patch.gg (coming soon) |
| Agents, scripts or CI | An API key, sent as `Authorization: Bearer pch_...`. With `pch`, set it as the `PCH_TOKEN` environment variable. |

```bash theme={null}
curl https://patch.gg/api/v1/me \
  -H "Authorization: Bearer $PCH_TOKEN"
```

### API keys

API keys start with `pch_` and belong to your account. Create one with [`POST /tokens`](https://docs.patch.gg/api-reference/account/create-an-api-key-for-an-agent-or-ci) while signed in to patch.gg; an API key can't create other keys. The key is shown once, so store it right away. Keys can expire after a number of days you choose, and you can revoke one at any time with `DELETE /tokens/{id}`.

A page for managing keys on patch.gg and `pch token create` are coming soon.

Each key has one or more scopes:

| Scope | Allows |
| - | - |
| `read` | Everything a signed-out visitor can see, plus the key owner's private data |
| `publish` | Creating projects and releases in orgs the owner can publish to |
| `admin` | Staff-only changes, such as editing the host game catalog |

A request whose key lacks a scope gets `403` with the code `missing_scope`.

## Errors

Errors use a 4xx or 5xx status and the same body:

```json theme={null}
{
  "error": {
    "code": "version_exists",
    "message": "mira/lantern-run@1.2.0 is already published",
    "details": {}
  }
}
```

`code` is stable, so branch on it; `message` is for people and can change. `details` holds more about the error when there is any, for example which files are missing.

| Code | Status | Means |
| - | - | - |
| `invalid_request` | 400 | The request doesn't match the API. `details.issues` lists each problem with its `path`. |
| `unauthorized` | 401 | Sign in, or send an API key |
| `invalid_api_key` | 401 | The API key is wrong, expired or revoked |
| `forbidden` | 403 | You're signed in but can't do this |
| `missing_scope` | 403 | The API key needs another scope |
| `not_found` | 404 | No such endpoint or record |
| `internal_error` | 500 | Something went wrong on Patch's side |

Endpoints add their own codes, such as `project_exists`, `manifest_invalid`, `files_missing` or `version_exists`.

## Conventions

* **JSON in snake\_case.** Timestamps are RFC 3339 in UTC.
* **Addressing.** Projects are addressed as `{owner}/{slug}` and releases by version. Everything also has a permanent `id`.
* **Renames.** A request that uses an owner's old name gets a `308` redirect to the new one. Most HTTP clients follow it for you.
* **Lists** take `limit` (default 20, at most 100) and `cursor`, and return `{ "data": [...], "next_cursor": "..." }`. Pass `next_cursor` back as `cursor` for the next page; it's `null` on the last one.
* **Safe retries.** `POST /projects` takes an `Idempotency-Key` header. Retrying with the same key returns the first response instead of creating a second project.
* **Compatibility.** Within `v1`, changes are additive only: new endpoints, new optional fields and new error codes. Ignore fields you don't know.

## Publishing a release

This is what `pch publish` does, and what any other client needs to do:

**1. Validate and hash**

Read [`patch.json`](https://docs.patch.gg/manifest), check it, and hash every file it includes with SHA-256.

**2. Create a draft**

`POST /projects/{owner}/{slug}/releases` with the `manifest`, the `files` as `{ path, sha256, size }`, and optionally a `changelog` and `channel`. Patch checks the manifest and creates a `draft` release.

The response has an upload target for each file Patch doesn't already have. Files Patch already has, from any release, are skipped.

**3. Upload**

Upload each file to its target URL. Files over 100 MB use a multipart upload, with one URL per part; finish each one with `POST /uploads/{id}/complete`.

**4. Submit**

`POST /projects/{owner}/{slug}/releases/{version}/submit`. Patch checks that every upload matches its hash and size, then queues the release for review.

Creating the same version again while it's still a draft resumes it, and files you already uploaded are skipped. Once a release is submitted, its version is taken (`version_exists`), and published releases never change.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.