Reliquary Pre-alpha
Docs menu

Docs / Reference

Env API

The HTTP API the Reliquary CLI uses to read environment variables and send pushes, for anyone building their own client.

The API lives on the web app, at https://app.reliquary.redmage.cc/api/env. It only accepts CLI sign-ins: an MCP token or connection is refused, and a CLI sign-in is refused at the MCP endpoint.

Signing in

OAuth 2.1 against the web app, as a public client:

Metadata GET /.well-known/oauth-authorization-server
Client id <server>/cli/oauth-client.json (the Reliquary CLI's own; no other client may ask for this API)
Resource <server>/api/env, exactly, at authorize, token and refresh
Redirect http://127.0.0.1:<any port>/callback or http://[::1]:<any port>/callback
PKCE S256 only
Access token starts rle_, lasts 1 hour
Refresh token starts rlr_, rotates on every use; presenting a used one revokes the whole sign-in. The sign-in lasts at most a year
Revoke POST /oauth/revoke with token and client_id; always 200

The answer to authorize carries code, state and iss; check that state is yours and iss is the server.

Requests

Send Authorization: Bearer rle_... on every request. Anything else gets:

401 {"error": "invalid_token"}
WWW-Authenticate: Bearer realm="reliquary", resource_metadata="<server>/.well-known/oauth-protected-resource/api/env"

Every answer is JSON, cache-control: no-store, private, with no CORS headers.

Every error carries its code in error (the codes below), and beside it message (what failed and why), where (the part of Reliquary that failed) and ref (a reference ID to quote when you report it). The message never echoes what you sent. A failure of the server itself is server_error with the status that fits it: 500, 503 when the database is unreachable, 504 when it timed out. Errors and reference IDs explains the fields.

{ "error": "forbidden", "message": "Reading production in vault 3f2a9c1d failed: Your role can't use this environment's values (a viewer, or an editor in an owners-only environment such as production).",
  "where": "database (your role)", "ref": "7f3a2c9e" }

Each sign-in may make 60 requests a minute and 5000 a day (Limits). Past that, any route answers 429 {"error": "rate_limited"} with Retry-After in seconds; wait that long and try again.

GET /api/env/vaults

The vaults the sign-in reaches, each with the environments your role may read (empty for a viewer). Reads no values, and isn't in the access log.

{ "vaults": [ { "id": "<uuid>", "name": "My project", "role": "owner",
                "environments": ["development", "preview", "production"] } ] }

GET /api/env/<vault id>/<environment>

Every variable with a value in that environment, decrypted, in name order. Logged in the vault's access log as a read, with the names.

{ "vault": "<uuid>", "environment": "development",
  "variables": { "API_KEY": "...", "DATABASE_URL": "..." } }
Status Body When
403 {"error": "forbidden"} your role can't read that environment (a viewer; an editor on an owners-only one). Logged as refused
404 {"error": "not_found"} the vault isn't reachable with this sign-in, or the environment doesn't exist
500 {"error": "decrypt_failed"} a value didn't decrypt; nothing is delivered, not even the others
503 {"error": "not_configured"} the server has no key for variables

POST /api/env/<vault id>/<environment>/imports

Sends variables for a person to apply (a push). Needs a sign-in allowed to send .env files. JSON, at most 1 MiB:

{ "variables": { "API_KEY": "...", "DATABASE_URL": "..." },
  "refused": [ { "line": 4, "name": "PATH", "reason": "changes how programs start" } ] }

refused (optional) lists lines your client didn't send, shown to the reviewer. The answer:

201 { "import": "<uuid>", "status": "pending", "vault": "<uuid>", "environment": "development",
      "names": ["API_KEY", "DATABASE_URL"], "overwrites": ["API_KEY"], "expires_at": "...",
      "url": "<server>/v/<vault>/variables/imports/<import>" }

Errors: 400 invalid_request (not JSON, a bad or refused name, an empty or oversized value; never echoed), 403 forbidden or push_not_allowed, 404 not_found, 413 too_large, 415 unsupported_media_type, 429 rate_limited, 503 not_configured, 507 storage_limit (the vault is at its storage limit: Plans and limits).

GET /api/env/imports/<import id>

The push's status, for the person who sent it: pending, applied, rejected or expired.

{ "import": "<uuid>", "status": "pending", "environments": ["development"],
  "names": ["API_KEY"], "expires_at": "...", "decided_at": null }

Other methods

Other methods get 405. Names follow the rules in Environment variables; limits are in Limits.

For agents: this page as Markdown, and every page at /llms.txt.