Versions

Write re-encrypted version entry ciphertext

Writes back version entry ciphertext that you re-encrypted client-side.

POST/projects/{slug}/environments/{environmentSlug}/versions/entries/reencrypt

Writes back version entry ciphertext that you re-encrypted client-side. The other half of the passphrase rotation pair, paired with GET .../versions/entries.

Only value and defaultValue are touched, and only for entries that belong to a version of this environment, so an id from another environment cannot be written through this route. Names, types and version metadata are untouched.

Rotate the version entries in the same run as the live variables. Rotating live values alone leaves the snapshots encrypted under the old key, which silently breaks any later rollback with no error at rotation time.

Two behaviours to code around. First, the endpoint is lenient rather than strict: entries whose id is not a valid uuid v7, or whose value is empty or longer than 20000 characters, are skipped without any error, and if every entry is skipped the response is still 200 with updated: 0. Always compare updated against the number of entries you sent and re-drive the difference. Second, defaultValue is written with a coalesce, so null or an omitted defaultValue keeps whatever is already stored. There is no way to clear a stored defaultValue through this route.

At most 200 entries per request. Requires both versions:write and variables:write.

Requires the versions:write or variables:write scope.

curl --request POST \
  --url 'https://api.envless.cloud/projects/<slug>/environments/<environmentSlug>/versions/entries/reencrypt' \
  --header 'Authorization: Bearer ev_sk_xxxxxxxxxxxx' \
  --header 'Content-Type: application/json' \
  --data '{
  "entries": [
    {
      "id": "0b0d3f1e-6c1a-4f2b-9a5e-2b7f0c9d4a13",
      "uniqueId": "0b0d3f1e-6c1a-4f2b-9a5e-2b7f0c9d4a13",
      "value": "v1:8Wm3kQ...ciphertext",
      "defaultValue": "<string>"
    }
  ]
}'
Try itPOSThttps://api.envless.cloud/projects/{slug}/environments/{environmentSlug}/versions/entries/reencrypt
Path parameters
Query 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

  • slugstringrequired

    Project slug or project uniqueId.

  • environmentSlugstringrequired

    Environment slug.

Query parameters

  • productstring

    Product slug, to disambiguate a project slug shared across products.

Request body

application/json · required

  • entriesobject[]requiredmin items 1max items 200
    Show child attributesHide child attributes
    • idstringuuid

      Entry id from GET .../versions/entries. uniqueId is accepted as an alias and wins when both are sent.

    • uniqueIdstringuuid

      Alias for id.

    • valuestringrequiredmin length 1max length 20000pattern ^v[12]:

      CIPHERTEXT re-encrypted with the new workspace key. The v1:/v2: prefix is NOT enforced on this endpoint, so a plaintext write here would succeed and corrupt the snapshot. Enforce it in your client.

    • defaultValuestring | nullmax length 20000pattern ^v[12]:

      CIPHERTEXT re-encrypted with the new key. null or omitted keeps the stored value, it does not clear it.

Responses

200OK

Write re-encrypted version entry ciphertext succeeded.

  • successbooleanrequired
  • codeintegerrequired

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

  • messagestringrequired
  • errornullrequired
  • dataobjectrequired
    Show child attributesHide child attributes
    • updatedintegerrequired

      Rows actually written. Lower than the number sent means some entries were skipped as invalid or did not belong to this environment.

  • _reqobject
    Show child attributesHide child attributes
    • reqIdstring
    • resTimeinteger | null
{
    "success": true,
    "code": 200,
    "message": "OK",
    "error": null,
    "data": {
        "updated": 1
    },
    "_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": 400,
    "message": "Something went wrong.",
    "error": {
        "code": "auth.api_key_required",
        "resource": "<string>",
        "field": "<string>"
    },
    "data": {},
    "_req": {
        "reqId": "<string>",
        "resTime": 1
    }
}

400Bad Request

request.body_invalid - entries is missing, empty or longer than 200, with error.field: "entries". request.body_must_be_json for an unparseable body.

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 project is locked by the plan's project limit.

403Forbidden

  • auth.scope_missing - the key lacks versions:write or variables:write, both are required. Also auth.key_project_restricted and auth.product_restricted for projects and products the key cannot reach.
  • auth.workspace_two_factor_required - the workspace requires two-factor authentication and the key's owner has not turned it on.

404Not Found

project.not_found - unknown project, or environment.not_found for an unknown environment slug.

409Conflict

project.ambiguous_product - the project slug exists under more than one product.

413Payload Too Large

request.body_too_large - the request body is larger than 1 MiB (1,048,576 bytes).

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.