/projects/{slug}/environments/{environmentSlug}/exposeToggles public exposure for one environment. An exposed environment serves its encrypted variables over a branded public URL, so anyone with the link gets ciphertext and still needs the workspace passphrase or key to read a value. Nothing is decrypted server-side.
Exposing is refused unless two independent flags line up: the workspace must have virtualEnvsEnabled on, set with PATCH /workspace, and the environment's product must not be private. Both are deliberate, so that a single accidental toggle cannot publish a feed.
Unexposing with { "exposed": false } needs neither flag and always succeeds, which makes it a safe kill switch. The public URL 404s uniformly the moment it lands, with no hint that the environment exists.
The project is resolved by slug or id. Pass product when the same project slug exists in more than one product.
Requires the environments:write scope.
curl --request POST \
--url 'https://api.envless.cloud/projects/<slug>/environments/<environmentSlug>/expose' \
--header 'Authorization: Bearer ev_sk_xxxxxxxxxxxx' \
--header 'Content-Type: application/json' \
--data '{
"exposed": true
}'https://api.envless.cloud/projects/{slug}/environments/{environmentSlug}/exposeResponse headers
Authorization
AuthorizationstringrequiredheaderBearer token: an Envless API key (
ev_sk_…), created in the dashboard or withPOST /keys. The key is bound to one workspace; every request runs inside it.
Path parameters
slugstringrequiredThe project slug or id that owns the environment.
environmentSlugstringrequiredThe environment slug to expose or unexpose.
Query parameters
productstringDisambiguates the project when the same slug exists in more than one product.
Request body
application/json · required
exposedbooleanrequiredTrue to serve the environment's encrypted variables publicly, false to stop.
Responses
200OK
Expose or unexpose an environment succeeded.
successbooleanrequiredcodeintegerrequiredThe HTTP status of this response, repeated in the body.
messagestringrequirederrornullrequireddataobjectrequiredShow child attributesHide child attributes
idstringrequirednamestringrequiredslugstringrequiredprojectIdstringrequiredexposedbooleanrequiredWhen true every published version is readable without an API key. Read-only here; change it in the dashboard.
createdAtstringrequireddate-timeupdatedAtstring | nulldate-time
_reqobjectShow child attributesHide child attributes
reqIdstringresTimeinteger | null
{
"success": true,
"code": 200,
"message": "OK",
"error": null,
"data": {
"id": "<string>",
"name": "<string>",
"slug": "<string>",
"projectId": "<string>",
"exposed": true,
"createdAt": "2026-05-30T10:14:22.000Z",
"updatedAt": "2026-05-30T10:14:22.000Z"
},
"_req": {
"reqId": "<string>",
"resTime": 1
}
}Error envelope
Every failure below returns the same shape with success: false; branch on error.code, never on message.
successbooleanrequiredcodeintegerrequiredThe HTTP status of this response, repeated in the body.
messagestringrequirederrorobjectrequiredMachine-readable failure detail. Null on success.
Show child attributesHide child attributes
codeenum<string>requiredStable 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"resourcestringThe resource or scope the failure relates to.
fieldstringThe request field that caused the failure.
dataobject | nullrequiredNull on most failures. A plan limit carries
{ limit, current }._reqobjectShow child attributesHide child attributes
reqIdstringresTimeinteger | 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_must_be_json- the body is not valid JSON.request.body_invalid-exposedis missing or not a boolean.
401Unauthorized
auth.api_key_required- theAuthorizationheader is missing, or its value does not start withev_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.
403Forbidden
auth.scope_missing- the key lacks environments:write.auth.key_project_restricted- the key is fenced to other projects.auth.product_restricted- the key owner has no grant on the private product that owns the project.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- no project in this workspace matches the slug or id.environment.not_found- the project has no environment with that slug.
409Conflict
project.ambiguous_product- the slug exists in more than one product and noproductwas given.environment.expose_disabled- the workspace hasvirtualEnvsEnabledoff.environment.expose_private_product- the owning product is private, which can never be exposed.
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.