# 14 — API contract ## Normative OpenAPI contract `api/openapi.yaml` is the machine-readable v1 contract. Route handlers, generated clients and contract tests must conform to it. Reusable error objects belong under `components.responses`; domain payloads belong under `components.schemas`. A prose endpoint in this document is not considered implemented until it exists in the OpenAPI file and has authorization plus response-contract tests. ## Principles - JSON over HTTPS; - explicit version prefix when public stability is required, starting with `/api/v1`; - OpenAPI generated or verified in CI; - consistent error shape; - cursor pagination for large collections; - idempotency keys for imports, generation and sync jobs; - ETags or version fields for mutable drafts and profiles; - authorization at use-case boundary. ## Error shape ```json { "error": { "code": "PLAYBOOK_VALIDATION_FAILED", "message": "The package contains validation errors.", "requestId": "req_...", "details": [ { "path": "spec.autonomy.default", "rule": "within-range", "message": "Default autonomy must be between min and max." } ] } } ``` Do not expose stack traces or upstream authorization headers. ## Playbooks ### `GET /api/v1/playbooks` Query: - `q` - `category[]` - `type[]` - `risk[]` - `lifecycle[]` - `autonomy[]` - `stack[]` - `source[]` - `sort` - `cursor` - `limit` Returns compact search records and match explanation. ### `GET /api/v1/playbooks/{slug}` Returns identity and latest recommended version. ### `GET /api/v1/playbooks/{slug}/versions/{version}` Returns complete safe package projection, not internal persistence details. ### `POST /api/v1/playbook-imports` Starts an import job from an uploaded ZIP or staged package. Multipart size limits apply. ### `POST /api/v1/playbooks/{id}/versions/{version}/publish` Private authoring capability. Requires validated draft state and reviewer permission in future team mode. ## Repositories ### `GET /api/v1/repositories` Lists accessible manual and connected repository records. ### `POST /api/v1/repositories` Creates manual repository identity and initial profile revision. ### `GET /api/v1/repositories/{id}/profile` Returns latest profile and revision metadata. ### `PUT /api/v1/repositories/{id}/profile` Creates a new revision using optimistic concurrency. ### `POST /api/v1/repositories/{id}/snapshots` Queues a read-only integration refresh. ### `GET /api/v1/repositories/{id}/snapshots/{snapshotId}` Returns normalized evidence and findings subject to user permissions. ## Composition ### `POST /api/v1/compositions/preview` Input: ```json { "playbook": {"slug": "root-cause-bugfix", "version": "1.0.0"}, "repositoryProfileRevisionId": "...", "workMode": "execute", "autonomyLevel": "verify", "inputs": {}, "scopeOverrides": {} } ``` Returns rendered preview, provenance, compatibility and lint findings. It does not create an immutable run. ### `POST /api/v1/runs` Same logical input plus an idempotency key. Creates immutable run only when blocking findings are absent. The guided composer also sends `X-DevRunbook-Draft-Id`; when present, the server reloads that authorized persisted draft as the authoritative source and records the relation on the generated run. ### `GET /api/v1/runs/{id}` Returns immutable snapshots and rendered output. ### `POST /api/v1/runs/{id}/artifacts` Input artifact type. Returns synchronous result for small Markdown or job reference for ZIP generation. ### `GET /api/v1/artifacts/{id}/download` Authorized download response with safe content disposition. ### `POST /api/v1/run-pack-imports` Accepts a bounded `application/zip` body and verifies archive path safety, declared inventory, file hashes, the canonical manifest digest and the exact embedded historical prompt digest in memory. The manifest run identity is then matched against the caller's authorized immutable run; the archive is never extracted and imported repository text is never executed. ## Integrations ### `GET /api/v1/integrations/gitea` Lists safe workspace-scoped connection metadata. Secret envelopes, tokens and authorization headers never appear in the response. ### `POST /api/v1/integrations/gitea` Creates connection. Token is write-only. ### `POST /api/v1/integrations/gitea/{id}/test` Tests and updates capability status. ### `GET /api/v1/integrations/gitea/{id}/repositories` Proxies normalized paginated repository discovery; never exposes token. ### `POST /api/v1/integrations/gitea/{id}/repositories/import` Imports one discovered identity idempotently, creates a collecting snapshot and queues the bounded read-only snapshot job. The request contains only the opaque external repository identity; the worker reloads all trusted integration state. ### `POST /api/v1/integrations/gitea/{id}/rotate-secret` Replaces token and records audit event. ### `DELETE /api/v1/integrations/gitea/{id}` Deletes/invalidates secret and detaches repositories after explicit confirmation policy. ## Jobs ### `GET /api/v1/jobs/{id}` Returns state, stage, progress and safe error. ### `POST /api/v1/jobs/{id}/retry` Allowed only for retryable failed jobs and authorized users. ## Health - `GET /health/live` — process alive; - `GET /health/ready` — required dependencies and migration state ready; - `GET /api/v1/admin/health` — authenticated detailed component health. ## Concurrency Mutable resources include `revision` or ETag. Updates with stale versions return `409 CONFLICT` and a safe diff or recovery instruction. ## Rate limits At minimum: - authentication; - integration tests; - repository snapshot creation; - imports; - composition preview bursts; - artifact generation. Self-hosted administrators can tune limits, but disabling all safeguards should require explicit configuration.