REST API Reference
The REST API is Envy’s authoritative control surface. It operates over HTTP with JSON payloads and conforms to the formal OpenAPI 3.1 specification (api/openapi.yaml). This page summarizes common composition endpoints; the OpenAPI file includes the complete catalog, source, frontend, installation, and recipe contracts. Response examples below show selected fields.
The draft, plan, and diagnosis routes were merged after v0.8.0 and require a newer source build until a release includes them.
Authentication & Headers
Section titled “Authentication & Headers”All /v1 endpoints use the installation’s configured authentication. CLI and machine clients send an Envy bearer token; browsers use a session cookie in password/Google mode. Explicit dev mode supplies the Admin identity automatically. For bearer requests:
Authorization: Bearer <token>Global Headers
Section titled “Global Headers”Authorization: Bearer <token>: Used for CLI, agent, and machine authentication. Cookie-authenticated mutations also require same-originOriginandX-CSRF-Tokenfrom/auth/config.Content-Type: application/json: Required forPOSTandPATCHrequests.Idempotency-Key: <string>: Optional unique identifier (up to 128 printable ASCII characters) to ensure safe retries.
Endpoints Summary
Section titled “Endpoints Summary”| Method | Path | Description | Status |
|---|---|---|---|
POST | /v1/compositions | Create a new ephemeral composition | 202 Accepted |
GET | /v1/compositions | List active compositions (paginated) | 200 OK |
GET | /v1/compositions/{id} | Get full desired and observed state | 200 OK |
GET | /v1/compositions/{id}/status | Get lightweight phase and latest operation | 200 OK |
GET | /v1/compositions/{id}/endpoints | Get preview URLs and routing readiness | 200 OK |
POST | /v1/compositions/plan | Review a read-only preview plan | 200 OK |
PATCH | /v1/compositions/{id} | Rolling image update with expected generation | 202 Accepted |
DELETE | /v1/compositions/{id} | Destroy composition asynchronously | 202 Accepted |
GET | /v1/compositions/{id}/components/{component}/logs | Fetch bounded container log snapshots | 200 OK |
GET | /v1/compositions/{id}/events | Durable audit events log | 200 OK |
GET | /v1/compositions/{id}/diagnosis | Explain recorded blockers and unknowns | 200 OK |
GET | /v1/compositions/{id}/verification | List retained checks with freshness | 200 OK |
GET | /v1/compositions/{id}/observability | Resolve configured external links | 200 OK |
POST | /v1/catalog/validate | Dry-run catalog validation | 200 OK |
POST | /v1/catalog/apply | Atomic catalog registration | 200 OK |
GET, PUT, DELETE | /v1/projects/{project}/onboarding-draft | Resume, save, or discard non-secret preparation | 200 / 204 |
GET | /v1/projects | List registered projects | 200 OK |
GET | /v1/projects/{project}/components | List approved component profiles | 200 OK |
GET | /v1/projects/{project}/baselines | List registered baselines | 200 OK |
Detailed Endpoint Schemas
Section titled “Detailed Endpoint Schemas”1. Create Composition
Section titled “1. Create Composition”POST /v1/compositionsAuthorization: Bearer <token>Content-Type: application/jsonIdempotency-Key: ci-pr-42-attempt-1
{ "project": "demo", "baseline": "staging", "name": "pr-auth-fix", "overrides": { "service-b": { "image": "envy/service-b:v2" } }, "ttl": "8h"}Response: 202 Accepted
Section titled “Response: 202 Accepted”Location: /v1/compositions/cmp-84f1a09
{ "id": "cmp-84f1a09", "project": "demo", "baseline": "staging", "name": "pr-auth-fix", "generation": 1, "observed_generation": 0, "phase": "created", "expires_at": "2026-09-12T04:20:00Z", "created_at": "2026-09-11T20:20:00Z", "endpoints": { "public": { "url": "http://cmp-84f1a09.envy.localhost:8080", "ready": false } }, "latest_operation": { "id": "op-01J98X7", "kind": "create", "status": "pending" }}Creation accepts zero to three overrides. Use "overrides": {} for a baseline-only preview. Each selected component supplies either {"image":"registry/image:tag"} or {"build_id":"BUILD_ID"}; Envy resolves build provenance and does not accept caller-provided source.
Send the same request body to POST /v1/compositions/plan to inspect the
selected images, inherited components, approved revisions, declared
dependencies, destination, lifetime, resource estimate, blockers, and cautions
before creation. Planning is read-only and does not reserve capacity. The
create request rechecks the current contract, so a ready plan does not guarantee
that a later create will succeed.
Optional "message_isolation": true enables Google Pub/Sub isolation at creation after operator/application setup. It defaults to false and is immutable. The composition response includes message_subscriptions for inspection and readiness.
2. Update Composition (Complete Override Selection)
Section titled “2. Update Composition (Complete Override Selection)”PATCH /v1/compositions/cmp-84f1a09Authorization: Bearer <token>Content-Type: application/json
{ "expected_generation": 1, "overrides": { "service-b": { "image": "envy/service-b:v3" } }}Optimistic Concurrency & Errors
Section titled “Optimistic Concurrency & Errors”- If the current generation does not match
expected_generation, the API responds with409 Conflict. overridesis the complete desired selection, not a partial patch. Add or remove components within the zero-to-three limit; omitted keys return to inheritance and{}removes all overrides.- The preview URL and original expiry stay the same. TTL and message isolation cannot be changed here.
- Only ready or failed, unexpired compositions can be updated. Concurrent rollout/deletion conflicts and generic updates to GitHub App-owned previews return
409. - Wait for the new generation to become ready before testing. Rolling updates are not atomic across components; a failed rollout can leave the previous override serving without switching it to the baseline.
3. Fetch Container Logs
Section titled “3. Fetch Container Logs”GET /v1/compositions/cmp-84f1a09/components/service-b/logs?tail_lines=50&since_seconds=600Authorization: Bearer <token>Response: 200 OK
Section titled “Response: 200 OK”{ "message": "returned log snapshots", "component": "service-b", "source": "override", "composition_filtered": false, "streams": [ { "pod": "cmp-84f1a09-service-b-7f4d", "container": "service-b", "text": "2026-09-11T20:22:01Z [info] server listening on :8080\n", "truncated": false } ], "partial": false, "truncated": false}If querying an unmodified baseline service (for example gateway), the
response identifies source as "shared-baseline" and the returned logs are
not filtered by composition baggage.
4. Delete Composition
Section titled “4. Delete Composition”DELETE /v1/compositions/cmp-84f1a09Authorization: Bearer <token>Response: 202 Accepted
Section titled “Response: 202 Accepted”The composition phase transitions to destroying. Cleanup is asynchronous, repeatable, and idempotent.
Preparation and diagnosis
Section titled “Preparation and diagnosis”GET, PUT, and DELETE /v1/projects/{project}/onboarding-draft manage one
draft per installation, project, and authenticated author. PUT requires the
current revision (0 creates a draft); DELETE requires ?revision=N.
Stale revisions return 409. Drafts exclude environment and selected ConfigMap
values, credentials, and messaging configuration. They do not register catalog
entries or create previews. Shared-token and anonymous modes use a common
draft author; person-level separation requires identity-bearing access.
GET /v1/compositions/{id}/diagnosis explains recorded conditions with
state, blockers, notes, verification, and optional evidence_id.
GET /v1/compositions/{id}/verification?limit=20&after=<next_cursor> retains
individual checks and derives freshness when read. A changed inherited image,
Service route, selected workload, or verification contract can invalidate old
proof without incrementing the composition generation. The API reports unknown
or unavailable coverage rather than inferring a successful result. See
Diagnostics & Error Codes for interpretation and
api/openapi.yaml for complete response schemas.
GitHub App and PR previews
Section titled “GitHub App and PR previews”See the setup and permissions guide before enabling a repository policy. These routes use the normal authenticated Envy API:
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/github/status | App configuration, webhook and reconciliation health. |
| GET | /v1/github/installations?page=1 | Discover App installations. |
| GET | /v1/github/installations/{id}/repositories?page=1 | Discover accessible repositories. |
| GET | /v1/github/preview-policies | List repository policies. |
| GET, PUT | /v1/projects/{project}/repositories/{repository}/preview-policy | Read or configure a policy. |
| GET | /v1/github/previews?project=shop&limit=20 | List previews; use after for pagination. |
| GET | /v1/github/previews/{id} | Preview detail and lifecycle status. |
| POST | /v1/github/previews/{id}/stop | Suppress automation and request cleanup. |
| POST | /v1/github/previews/{id}/restart | Request a fresh lifecycle for an open labelled PR. |
Stop/restart return 200 when accepted; resource transitions are asynchronous.
Full request/response schemas are in the
OpenAPI specification.
POST /webhooks/github is a separate public ingestion route authenticated with
the GitHub raw-body HMAC signature, not an Envy bearer token. Valid deliveries are
persisted and deduplicated before 202 Accepted, then processed asynchronously.