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

# Act for an installation

> List an installation's repositories, mint access tokens for them, and create new ones.

Two Core endpoints take your [plugin JWT](https://docs.entire.com/guides/api/authentication.md#plugin-jwts): list repositories and mint an access token. Everything else takes an access token and goes to the [repository's region](https://docs.entire.com/guides/api/regions-and-routing.md), except [creating a repository](#create-a-repository), which takes an access token on a Core.

## List repositories

```http theme={null}
GET https://{core}/api/v1/plugins/{slug}/installations/{installation_id}/repositories
Authorization: Bearer {plugin JWT}
```

The response lists every repository the customer selected:

```json theme={null}
{
  "repositories": [{
    "id": "repo_01M3...",
    "full_name": "acme/api",
    "clone_url": "https://aws-us-east-2.entire.io/et/acme/api.git",
    "entire_clone_url": "entire://aws-us-east-2.entire.io/et/acme/api",
    "placements": [
      {"region": "aws-us-east-2", "role": "processing_primary",
       "api_base_url": "https://aws-us-east-2.api.entire.io"},
      {"region": "aws-eu-central-1", "role": "mirror"}
    ]
  }],
  "next_cursor": null
}
```

Store a repository's `id`, which never changes. Names and hosts can change, so list the repositories again rather than caching them for long. Customers change the selection without notice; this list is the authority on what you may touch.

## Mint an access token

```http theme={null}
POST https://{core}/api/v1/plugins/{slug}/installations/{installation_id}/access-tokens
Authorization: Bearer {plugin JWT}
Content-Type: application/json

{"repository_id": "repo_01M3...", "permissions": {"contents": "read"}}
```

A successful mint answers `201`:

```json theme={null}
{"token": "...", "username": "x-access-token", "expires_at": "2026-10-13T20:37:23Z", "permissions": {"contents": "read", "installations": "read"}}
```

Prefer a token scoped to one repository. See [Access tokens](https://docs.entire.com/guides/api/authentication.md#access-tokens) for what each combination of repository and permissions reaches.

## Errors

| Status and code | Meaning | What to do |
| :- | :- | :- |
| `401 unauthorized` | Entire could not verify your plugin JWT: wrong key, issuer, audience or times. | Check the [claims table](https://docs.entire.com/guides/api/authentication.md#plugin-jwts) and your server clock. |
| `404 not_found` | The installation is gone, or the repository is not in it. | Stop acting for it. List the repositories again. |
| `400 unsupported_permission` | You asked for a permission you did not register. | Request only registered permissions. |
| `400 invalid_request` | You asked for `repositories:create` with a `repository_id`. | Mint a create token without a repository. |
| `409 coverage_changed` | The customer changed the selection while Entire minted the token, or you asked for a permission this installation doesn't have yet. | Retry the mint. If it persists after a permission change, ask your Entire contact. |
| `429 rate_limited` | Too many mints for this installation. | Wait for `Retry-After`, in seconds, and cache tokens until shortly before they expire. |
| `403 forbidden` | Entire refused to issue the token. | Don't retry in a loop. If it persists, ask your Entire contact. |
| `502`, `503`, `504` | Temporary. | Retry with backoff. |

Error bodies are RFC 9457 problem documents, with a machine-readable `code` member.

## Create a repository

A plugin registered with `repositories:create` can create repositories in the installation's project. The customer sees "Create repositories in this project" on the install page. The permission only creates: it doesn't read or write contents, delete repositories or change settings. To push to a repository you created, register `contents:write` too.

First mint a token with no `repository_id`:

```http theme={null}
POST https://{core}/api/v1/plugins/{slug}/installations/{installation_id}/access-tokens
Authorization: Bearer {plugin JWT}
Content-Type: application/json

{"permissions": {"repositories": "create"}}
```

The response carries `"permissions": {"repositories": "create", "installations": "read"}`. The token reaches no repository. The installation-wide token, minted with every permission you registered, also creates.

Then create the repository on the same Core:

```http theme={null}
POST https://{core}/api/v1/repos
Authorization: Bearer {access token}
Content-Type: application/json

{"name": "api", "objectFormat": "sha1"}
```

`objectFormat` is optional: `sha1`, the default, or `sha256`. Leave out `projectId`, and Core uses the installation's project. Any other project answers `404`. Plugins can't set `clusterHost` or `mirrorClusterSlugs`.

A successful create answers `201` with the repository:

```json theme={null}
{"repositoryId": "repo_01M3...", "name": "api", "owningProjectId": "...", "state": "provisioning", ...}
```

Store `repositoryId`. It is the `id` the repository list, access tokens and webhooks use. Core answers only once the installation covers the new repository, so you can [mint a token for it](#mint-an-access-token) right away. If the customer selected a list of repositories, the new one joins it. Every installation that covers it receives `installation.repositories_added`.

### Wait for provisioning

When `state` is `active`, the repository is ready. When it is `provisioning`, Git and region API calls fail until it's ready. [List the installation's repositories](#list-repositories) until the new one has a placement whose role is `processing_primary`, then send calls to that placement's `api_base_url`.

### Create errors

Core answers a refused create with an [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) problem document. Branch on its `type`, not on the status alone: `409` and `429` carry other conditions too.

| Status and `type` | Meaning | What to do |
| :- | :- | :- |
| `400` | The name or body is invalid, or you sent `clusterHost` or `mirrorClusterSlugs`. | Fix the request. |
| `401` | The token expired, or the customer uninstalled your plugin. | Mint a new token. Stop if the installation is gone. |
| `403` | The token lacks `repositories:create`. | Mint a token with `{"repositories": "create"}`. |
| `403` `https://entire.com/errors/plugins/installation-suspended` | The installation is suspended. | Stop creating until it is active again. |
| `404` | The project doesn't exist, or isn't the installation's project. | Leave out `projectId`. |
| `409` `https://entire.com/errors/repo/name-in-use` | The project already has a repository with that name. | Pick another name, or list the repositories to find the existing one. |
| `429` `https://entire.com/errors/repo/create-limit-reached` | The installation reached its create limit. | Wait for `Retry-After`, in seconds. |
| `503` | Temporary. | Retry with backoff. |

A create is not idempotent. If the connection drops before you read the response, list the installation's repositories before you create again: a `409` can mean your own earlier create succeeded.

### Limits and ownership

An installation can create 100 repositories in any 24 hours. To raise the limit, ask your Entire contact.

The customer's project owns every repository you create. The repositories stay when the customer uninstalls your plugin. The customer can remove one from the installation's selection like any other repository, and then you lose access to it.
