// docs

API Quickstart

Create an API key and pull your first environment variable over REST in under a minute.

API Quickstart

Envpilot's public REST API lets you read projects, variables, and shared accounts programmatically — no CLI or extension required. It's read-only in v1 and requires the Pro plan.

Create an API key#

Go to Organization Settings → API Keys — there's a single creation screen; project scope is a choice you make inside it, not a separate settings page.

  1. Click New API Key
  2. Choose a scope (see below) — pick specific projects, or "all projects, including future ones" (owner-only)
  3. Copy the key — it's shown once, as envpk_.... Envpilot only stores a hash of it; if you lose it, revoke it and create a new one — there's no rotate-in-place.

Org-wide keys (scope = all projects) can only be created by the organization Owner. Project-scoped keys can also be created by a Team Lead.

Understand scope#

Every key has three independent scope dimensions:

  • Projectsall (every project in the org) or a specific list of projects
  • Environmentsall (development, staging, production) or a specific list
  • Resources — which resource types the key can read: variables, accounts, projects, and optionally requests (the one write path — filing a variable request for a human to approve)

A key also carries surfaces — which faces it may use: the REST API (rest_api), the MCP server (mcp_server), and the GitHub Action (github_action). All three route through the same enforcement core; see Architecture.

A key requesting a project outside its scope gets a 404 — identical to a project that genuinely doesn't exist, so a leaked key can't be used to probe which project slugs are real. A key requesting a resource type, environment, or surface outside its scope gets a 403 instead, since the project's existence is already implied by a URL the key can otherwise reach. This is deliberate: see API Security for why.

Pull your first variables#

terminal
curl https://www.envpilot.dev/api/v1/projects/backend/variables?environment=production \
  -H "Authorization: Bearer envpk_your_key_here"

Response:

json
{
  "variables": [
    {
      "key": "DATABASE_URL",
      "value": "postgres://...",
      "environments": ["production"],
      "isSensitive": true,
      "updatedAt": 1752192000000
    },
    {
      "key": "API_SECRET",
      "value": "sk_live_...",
      "environments": ["staging", "production"],
      "isSensitive": true,
      "updatedAt": 1752192000000
    }
  ]
}

environment is required unless you pass metadata_only=true. Each variable's environments array is its full scope — a key shared across staging and production shows both, even though you asked for production only. With metadata_only=true, the value field is omitted entirely (no vault round-trip happens).

Filtering#

Exact keys — pull only the variables you name:

terminal
curl "https://www.envpilot.dev/api/v1/projects/backend/variables?environment=production&keys=DATABASE_URL,API_SECRET" \
  -H "Authorization: Bearer envpk_your_key_here"

Prefix match — useful for grabbing a related group, e.g. everything exposed to the client:

terminal
curl "https://www.envpilot.dev/api/v1/projects/backend/variables?environment=production&prefix=NEXT_PUBLIC_" \
  -H "Authorization: Bearer envpk_your_key_here"

Metadata only — list variable keys without decrypting any values (no vault round-trip, higher rate limit):

terminal
curl "https://www.envpilot.dev/api/v1/projects/backend/variables?metadata_only=true" \
  -H "Authorization: Bearer envpk_your_key_here"

dotenv output — get a ready-to-write .env file instead of JSON:

terminal
curl "https://www.envpilot.dev/api/v1/projects/backend/variables?environment=production&format=env" \
  -H "Authorization: Bearer envpk_your_key_here"
# DATABASE_URL=postgres://...
# API_SECRET=sk_live_...

Handling errors#

Every error response — across all v1 endpoints — has the same shape: { "error": "<message>", "code": "<CODE>" }, plus an x-request-id header worth logging for support.

StatusCodeMeaning
400VALIDATION_ERRORMissing or malformed query params (e.g. no environment and no metadata_only=true)
401MISSING_TOKENNo Authorization: Bearer header
401INVALID_KEYKey is unknown, revoked, or expired — all three look identical to the caller
403FORBIDDEN_SCOPEKey doesn't include this resource type or environment
403FORBIDDEN_SURFACEKey isn't enabled for this surface (REST vs. MCP vs. GitHub Action)
403TIER_GATEOrganization's plan no longer includes the public API
404NOT_FOUNDProject outside the key's scope, or genuinely doesn't exist — see Understand scope
422OVERFLOWProject exceeds the 1000-row bounded-read cap — see Bounded reads
429RATE_LIMITEDBucket exceeded — see Rate limits
503DECRYPT_FAILEDVault couldn't decrypt one of the values in this pull
503CONFIG_ERRORServer-side misconfiguration, not your key
500INTERNAL_ERRORUnrecognized failure
terminal
curl -i "https://www.envpilot.dev/api/v1/projects/backend/variables?environment=production" \
  -H "Authorization: Bearer envpk_a_revoked_key"
# HTTP/1.1 401 Unauthorized
# {"error":"Invalid or revoked API key","code":"INVALID_KEY"}

Bounded reads, no pagination#

There's no cursor or page parameter on any read endpoint — keys, prefix, and metadata_only are filters, not pagination. A pull is all-or-nothing up to 1000 active rows per project (variables and accounts each). If a project has more than that, the request fails outright with 422 OVERFLOW and a message telling you to contact support to raise the limit — you will never get a silently-truncated partial page back.

The same "loud, not partial" rule applies to decryption: if any single value in the pull fails to decrypt, the whole request fails with 503 DECRYPT_FAILED naming the offending key. Nothing decrypted so far is returned — Envpilot would rather fail a pull than hand back a response with one variable silently missing.

Retrying#

Envpilot's public API fails closed: every denial and every partial-data risk turns into a full request failure with a specific code, not a degraded response. That makes the retry decision mechanical:

  • 429 RATE_LIMITED — respect the Retry-After header (seconds) before retrying the identical request. See Rate limits for the per-bucket windows.
  • 503 DECRYPT_FAILED — retryable; vault errors are usually transient. If it persists across retries, the variable needs to be re-saved in Envpilot rather than pulled again.
  • 503 CONFIG_ERROR / 500 INTERNAL_ERROR — retryable with backoff; these are server-side, not caused by your request.
  • 401 / 403 / 404 / 422 — not retryable as-is. These only change if you fix the actual cause: rotate a revoked key, widen the key's scope, or shrink the project below the 1000-row cap.

Next steps#

  • API Reference — every endpoint, filter, and error code
  • Architecture — the five client surfaces and the one auth core
  • MCP Server — connect an AI agent (Claude, Cursor) directly to your variables
  • Rate limits — every per-key bucket and what happens when you exceed it
  • API Security — key model, scoping, revocation, and audit