# Control API /v1

The Scribase management API is an authenticated HTTP/1.1 REST API that manages
organizations, projects, environments, migrations, branches, queues, and more.

## Base URL

| Deployment | Base URL |
|---|---|
| Hosted Scribase | `https://api.scribase.com` |
| Your own cluster (by agreement) | Your own gateway, e.g. `https://api.<your-domain>` |

In your own cluster, the server listens on `127.0.0.1:8080` by default and requires a
TLS-terminating proxy or Ingress in front of it for production use. The CLI
reads the base URL from `SCRIBASE_API_URL`; the SDK takes it as `baseUrl`.

## Authentication

All endpoints except `/health/live` and `/health/ready` require a Bearer token:

```http
Authorization: Bearer <token>
```

On hosted Scribase, create a personal access token in the console under
**Account → Access tokens**, or via
[`POST /v1/account/tokens`](https://docs.scribase.com/docs/api/tokens.md). Organization API keys for CI and
services are created under **Organization → API tokens** or via
[`POST /v1/organizations/{org}/api-keys`](https://docs.scribase.com/docs/api/tokens.md). See the
[hosted quickstart](https://docs.scribase.com/docs/hosted.md) for the full sign-up-to-first-call path.

The token is verified via OIDC token introspection. Organization-level
authorization is then enforced by RLS membership state — the token's claims are
not used for authorization.

## Common request requirements

- `Content-Type: application/json` on all requests with a body.
- `Idempotency-Key: <key>` on all mutating endpoints (PUT, POST, DELETE). Keys must be 8–128 printable ASCII characters.
- `X-Scribase-Organization-ID: <org>` on the `operations` endpoint.

## Error format

Errors follow [RFC 9457 Problem Details](https://www.rfc-editor.org/rfc/rfc9457)
with `Content-Type: application/problem+json`. The `type` is a URN, not a web
page, and the machine-readable `code` is repeated as its own field so clients
can branch on it directly:

```json
{
  "type": "urn:scribase:error:route_not_found",
  "title": "Not found",
  "status": 404,
  "code": "route_not_found",
  "detail": "the requested management API route does not exist"
}
```

Common codes include `invalid_json` (400), `missing_idempotency_key` (400),
`unsupported_media_type` (415), `unauthorized` (401), `forbidden` (403),
`route_not_found` (404), `conflict` (409), and `server_busy` (503). The SDK maps each
status to a typed error class (`NotFoundError`, `ConflictError`,
`QuotaExceededError`, ...).

## Asynchronous operations

Endpoints that change environment state return `202 Accepted` with an
`Operation` document:

```json
{
  "id": "op_01J...",
  "kind": "create_environment",
  "environment": {
    "organization_id": "acme",
    "project_id": "store",
    "environment_id": "production"
  },
  "state": "pending",
  "attempt_count": 0
}
```

`state` moves through `pending`, `running`, and `waiting_retry` to one of the
terminal states `succeeded`, `failed`, or `cancelled`.

Poll `GET /v1/operations/{id}` (with `X-Scribase-Organization-ID`) until
`state` is terminal. The SDK's `operations.wait()` does this
automatically.

## Resources

| Resource | Endpoint prefix | Description |
|---|---|---|
| [Access tokens & API keys](https://docs.scribase.com/docs/api/tokens.md) | `/v1/account/tokens`, `.../api-keys` | Credentials for the CLI, SDK, and CI |
| [Organizations](https://docs.scribase.com/docs/api/organizations.md) | `/v1/organizations` | Tenant-level containers |
| [Projects](https://docs.scribase.com/docs/api/projects.md) | `/v1/organizations/{org}/projects` | Logical groupings within an org |
| [Environments](https://docs.scribase.com/docs/api/environments.md) | `/v1/environments` | Postgres environments, previews, TTL renewal, usage |
| [Backups & restore](https://docs.scribase.com/docs/api/backups.md) | `.../environments/{env}/backups`, `.../backups/{id}/restore` | Verified backups and restore |
| [Exports](https://docs.scribase.com/docs/api/exports.md) | `.../environments/{env}/exports`, `.../projects/{project}/export` | Runnable, signed export bundles |
| [Migrations](https://docs.scribase.com/docs/api/migrations.md) | `.../environments/{env}/migrations` | Schema migrations |
| [Branches](https://docs.scribase.com/docs/api/branches.md) | `.../projects/{project}/branches` | Schema-level branches |
| [Queues](https://docs.scribase.com/docs/api/queues.md) | `.../environments/{env}/queues` | Durable message queues |
| [Imports](https://docs.scribase.com/docs/api/imports.md) | `/v1/imports` | Live project migration |
| [Operations](https://docs.scribase.com/docs/api/operations.md) | `/v1/operations` | Async operation polling |
| [Audit Events](https://docs.scribase.com/docs/api/audit.md) | `.../audit-events` | Organization audit log |
| [Data-plane views](https://docs.scribase.com/docs/api/data-plane.md) | `.../environments/{env}/{auth,database,storage,functions,realtime,metrics,insights,logs}` | Read-only views into a live environment |

## OpenAPI spec

The server embeds its OpenAPI contract. Print it with:

```sh
scribase-control-api openapi
# or via HTTP:
curl http://localhost:8081/openapi.yaml
```
