Versions

Get a version

Returns one snapshot with its captured variables, addressed by version id and scoped to the workspace behind the API key.

GET/versions/{id}

Returns one snapshot with its captured variables, addressed by version id and scoped to the workspace behind the API key. There is no environment-scoped read for a single version, ids are the only way in.

Each entry is { name, value } and value is the ciphertext exactly as it stood when the version was taken. The server cannot decrypt it. Decrypt with the workspace key that was in force at snapshot time, which is the reason a passphrase rotation must rewrite version entries as well as live variables.

The snapshot also stores defaultValue, type, isSecret, visibility and required per entry, and a rollback restores all of them, but this response deliberately exposes only name and value. Use GET .../versions/entries if you need the stored defaultValue ciphertext.

Entries are sorted by name. Requires both versions:read and variables:read.

Plan gate. Free workspaces can read only the latest version of each environment. Any older version returns 402 plan.upgrade_required with error.resource: "version" and data: null; the check runs after the existence check, so a 402 confirms the version exists. Dev, Team and Enterprise read every version.

Requires the versions:read or variables:read scope.

curl --request GET \
  --url 'https://api.envless.cloud/versions/<id>' \
  --header 'Authorization: Bearer ev_sk_xxxxxxxxxxxx'
Try itGEThttps://api.envless.cloud/versions/{id}
Path parameters

Authorization

  • Authorizationstringrequiredheader

    Bearer token: an Envless API key (ev_sk_…), created in the dashboard or with POST /keys. The key is bound to one workspace; every request runs inside it.

Path parameters

  • idstringrequireduuid

    Version uniqueId (uuid v7). Labels such as v3 are not accepted.

Responses

200OK

Get a version succeeded.

  • successbooleanrequired
  • codeintegerrequired

    The HTTP status of this response, repeated in the body.

  • messagestringrequired
  • errornullrequired
  • dataobjectrequired
    Show child attributesHide child attributes
    • idstringrequired
    • labelstringrequired
    • notestring | null
    • variableCountintegerrequired
    • environmentIdstringrequired
    • createdAtstringrequireddate-time
    • variablesobject[]required
      Show child attributesHide child attributes
      • namestringrequired
      • valuestring | null

        CIPHERTEXT as captured. Decrypt with the workspace key in force when the version was taken.

  • _reqobject
    Show child attributesHide child attributes
    • reqIdstring
    • resTimeinteger | null
{
    "success": true,
    "code": 200,
    "message": "OK",
    "error": null,
    "data": {
        "id": "<string>",
        "label": "<string>",
        "note": "<string>",
        "variableCount": 1,
        "environmentId": "<string>",
        "createdAt": "2026-05-30T10:14:22.000Z",
        "variables": [
            {
                "name": "STRIPE_SECRET_KEY",
                "value": "<string>"
            }
        ]
    },
    "_req": {
        "reqId": "<string>",
        "resTime": 1
    }
}

Error envelope

Every failure below returns the same shape with success: false; branch on error.code, never on message.

  • successbooleanrequired
  • codeintegerrequired

    The HTTP status of this response, repeated in the body.

  • messagestringrequired
  • errorobjectrequired

    Machine-readable failure detail. Null on success.

    Show child attributesHide child attributes
    • codeenum<string>required

      Stable error code. Branch on this, never on message.

      Options: "auth.api_key_required", "auth.api_key_not_found", "auth.api_key_user_missing", "auth.api_key_owner_not_member", "auth.scope_missing", "auth.scope_ceiling_exceeded", "auth.key_project_restricted", "auth.product_restricted", "auth.permission_denied", "auth.self_mutation_forbidden", "auth.step_up_required", "auth.step_up_fresh_required", "auth.cli_token_not_accepted", "auth.two_factor_required", "auth.workspace_two_factor_required", "auth.two_factor_invalid", "auth.two_factor_replayed", "auth.two_factor_locked", "auth.two_factor_not_enabled", "auth.two_factor_already_enabled", "request.body_must_be_json", "request.body_invalid", "request.body_too_large", "request.rate_limited", "request.invalid_pagination", "workspace.not_found", "workspace.slug_conflict", "workspace.limit_reached", "workspace.delete_last", "workspace.delete_too_early", "workspace.delete_has_projects", "domain.not_configured", "domain.not_found", "domain.invalid", "domain.taken", "domain.attempt_limit", "product.not_found", "product.slug_conflict", "product.locked", "project.not_found", "project.ambiguous_product", "project.slug_conflict", "environment.not_found", "environment.slug_conflict", "environment.expose_disabled", "environment.expose_private_product", "variable.not_found", "variable.name_conflict", "variable.ciphertext_invalid", "variable.baseline_drifted", "version.not_found", "member.not_found", "member.already_exists", "member.self_invite", "member.self_mutation", "member.owner_immutable", "member.owner_cannot_leave", "member.seat_limit", "invite.already_pending", "role.owner_not_assignable", "role.limit_reached", "role.immutable", "role.in_use", "invite.not_found", "invite.expired", "role.not_found", "role.name_conflict", "key.not_found", "key.limit_reached", "webhook.not_found", "webhook.delivery_not_found", "plan.limit_reached", "plan.upgrade_required", "request.not_found", "request.method_not_allowed", "request.conflict", "auth.unauthorized", "auth.forbidden", "request.invalid", "server.error"

    • resourcestring

      The resource or scope the failure relates to.

    • fieldstring

      The request field that caused the failure.

  • dataobject | nullrequired

    Null on most failures. A plan limit carries { limit, current }.

  • _reqobject
    Show child attributesHide child attributes
    • reqIdstring
    • resTimeinteger | null
{
    "success": false,
    "code": 401,
    "message": "Something went wrong.",
    "error": {
        "code": "auth.api_key_required",
        "resource": "<string>",
        "field": "<string>"
    },
    "data": {},
    "_req": {
        "reqId": "<string>",
        "resTime": 1
    }
}

401Unauthorized

  • auth.api_key_required - the Authorization header is missing, or its value does not start with ev_sk_.
  • auth.api_key_not_found - the key is unknown, inactive or revoked.
  • auth.api_key_user_missing - the key is valid but its owner no longer exists.
  • auth.api_key_owner_not_member - the key's owner is no longer a member of the key's workspace.

402Payment Required

plan.upgrade_required - the version's project is locked by the plan's project limit, or the workspace is on the Free plan and the version is not the latest one in its environment. In the second case error.resource is version and data is null; upgrade to read older versions.

403Forbidden

  • auth.scope_missing - the key lacks versions:read or variables:read, both are required. Also auth.key_project_restricted and auth.product_restricted when the key or its owner cannot reach the version's project or product.
  • auth.workspace_two_factor_required - the workspace requires two-factor authentication and the key's owner has not turned it on.

404Not Found

request.not_found - no version with that id in this workspace. The check runs before any project restriction, so a 403 on this route confirms the version exists.

500Internal Server Error

server.error - an unexpected error; retry with backoff.

503Service Unavailable

server.error - the API is in maintenance mode or is missing its configuration; retry with backoff.

On the Free plan only the latest version of an environment is readable. Any older id answers 402 with error.code plan.upgrade_required, error.resource version and Your plan keeps only the latest version. Upgrade to browse, compare or restore earlier versions. Older versions and rollback need Dev or above. See Plans and billing.