# The HTTP API

> Every netweft route is described by an OpenAPI 3.1 document, every failure carries a named code a client can branch on, and every paid call answers 402 with the shortfall rather than billing for it afterwards.

Source: https://netweft.com/api

The dashboard is a client of this API and nothing more. Every route is described by an OpenAPI 3.1 document served from the API itself at `GET /openapi.json`, generated from the route definitions rather than written beside them.

## Authentication

- The dashboard authenticates with a session cookie, created by signing in with Google, GitHub or an email address and a password.
- The MCP server at `POST /mcp` authenticates with an API key, sent as `Authorization: Bearer` or `x-api-key`, narrowed to some of 6 scopes. The other routes take only the session cookie.
- A key is looked up by its public prefix and decided by a constant-time comparison against a stored SHA-256 hash. It is shown once, can carry an expiry, and is revoked rather than deleted.

## Named failures

A failing response carries a human sentence in `error` and a stable machine code in `code`. Each code has exactly one HTTP status.

| Code | Status | Meaning |
| --- | --- | --- |
| `insufficient_credits` | 402 | The workspace cannot cover the call. Answered before the vendor is reached, so nothing was bought and nothing was charged. available and required come with it, so a client can say by how much. |
| `rate_limited` | 429 | The fixed window is full. A Retry-After header comes with it, so a client library backs off on a number rather than on a guess. |
| `insufficient_role` | 403 | The caller is in the workspace but not with a role that may do this. Distinct from not being a member at all: the fix is a role change, not an invitation. |
| `background_unavailable` | 503 | The background service that runs audits and scheduled checks is unreachable. Nothing was charged and nothing was lost — the run simply cannot start yet. |

## Rate limits

Every policy is a fixed window. A refused request carries `Retry-After`.

- **Spending endpoints** (per user): 60 requests per 60s. Keyed per user rather than per workspace, so a team of ten is not throttled by one member's script.
- **API key requests** (per key): 120 requests per 60s. Applied at the MCP endpoint against the key's public prefix.
- **Trial workspaces** (per workspace): 10 requests per 60s. Tighter while a workspace is on trial, and back to the normal policy the moment it is not.
