# API

## Tokens

Create tokens in **Settings › API tokens**. A token acts as you in one workspace, limited to the scopes you choose, and stops working if you leave the workspace. It is shown once; HostEdge stores only a hash. Send it as a bearer token:

```sh
curl -H "Authorization: Bearer $HOSTEDGE_TOKEN" https://hostedge.app/api/v1/me
```

| Scope               | Allows                                 |
| ------------------- | -------------------------------------- |
| `projects:read`     | List and read projects and deployments |
| `projects:write`    | Create and change projects             |
| `deployments:write` | Upload files and create deployments    |
| `logs:read`         | Read runtime logs                      |
| `env:read`          | Pull environment variables             |
| `env:write`         | Change environment variables           |

Members, billing, tokens, webhooks and deleting things are never available to tokens. They need a signed-in person.

## Endpoints

The full description is at [`/api/v1/openapi.json`](https://hostedge.app/api/v1/openapi.json) (OpenAPI 3.1), for generating a client:

```sh
npx openapi-typescript https://hostedge.app/api/v1/openapi.json -o hostedge-api.d.ts
```

| Method and path                        | Purpose                                                                     |
| -------------------------------------- | --------------------------------------------------------------------------- |
| `GET /api/v1/me`                       | The person, workspace and scopes of the token                               |
| `GET /api/v1/projects`                 | Projects in the token's workspace                                           |
| `POST /api/v1/projects`                | Create a project (`name`, `settings`)                                       |
| `GET /api/v1/projects/:id/deployments` | Deployments, newest first                                                   |
| `POST /api/v1/uploads`                 | Which of these content hashes still need uploading (`hashes`)               |
| `PUT /api/v1/uploads/:hash`            | Upload one file's bytes                                                     |
| `POST /api/v1/uploads/batch`           | Upload many small files at once (multipart, each field named by its hash)   |
| `POST /api/v1/deployments`             | Create a deployment from uploaded files (`files`, `projectId` or `project`) |
| `GET /api/v1/deployments/:id/events`   | Build log and status as Server-Sent Events                                  |
| `GET /api/v1/deployments/:id/explain`  | Why a deployment failed, with fixes and a prompt for an AI assistant        |
| `GET /api/v1/projects/:id/logs`        | Runtime logs (`level`, `q`, `range`, `before`)                              |
| `GET /api/v1/projects/:id/env`         | Variables for an environment (`format=dotenv` for a file)                   |

### Explaining a failed deployment

`GET /api/v1/deployments/:id/explain` turns the failure reason and the last 300 lines of the build log into a diagnosis, without calling an AI model. It needs the `projects:read` scope and works for failed, canceled, held and rejected deployments; for a running or successful one it answers `{ "applicable": false, "reason": "in_progress" | "succeeded" }`.

```json
{
  "applicable": true,
  "deploymentId": "dep_…",
  "status": "failed",
  "reviewStatus": "none",
  "explanation": {
    "category": "missing-module",
    "ruleId": "module-not-found",
    "title": "Package “date-fns” couldn’t be found",
    "summary": "…",
    "likelyCause": "…",
    "fixes": ["Run `npm install date-fns` …"],
    "settingsToCheck": [{ "field": "Root directory", "suggestion": "…" }],
    "docsPath": "/docs/frameworks",
    "confidence": "high",
    "assistantPrompt": "A deployment of my project on HostEdge …"
  }
}
```

`assistantPrompt` is ready to paste into an AI assistant. It contains the framework, settings, diagnosis and at most 40 log lines, with tokens, bearer headers and `KEY=value` secrets removed. Explanations are rate limited to 120 requests a minute per workspace.

Errors are JSON: `{ "error": { "code": "forbidden", "message": "…" } }`. Tokens are rate limited to 600 requests a minute.
