POST /v1/env/list
List all variables in a stage. Returns metadata only — no plaintext values are included in this response.Request
| Field | Type | Required | Description |
|---|---|---|---|
orgSlug | string | Yes | Org slug |
projectSlug | string | Yes | Project slug |
stageSlug | string | Yes | Stage name |
Response
variables:
| Field | Type | Always present | Description |
|---|---|---|---|
name | string | Yes | Variable name |
kind | "secret" | "ab_roll" | Yes | Variable kind |
declaredType | string | No | Declared type, if set |
chance | number | ab_roll only | Probability of returning value A (0.0–1.0) |
createdAtMs | number | Yes | Unix timestamp in milliseconds |
updatedAtMs | number | Yes | Unix timestamp in milliseconds |
Error codes
| Code | HTTP | When |
|---|---|---|
UNAUTHORIZED | 401 | Invalid or expired token |
INVALID_JSON | 400 | Request body is not valid JSON |
INVALID_REQUEST | 400 | Missing required field |
INVALID_ORG_SCOPE | 403 | Token org doesn’t match orgSlug |
POST /v1/env/write
Create, update, or delete variables in a single request. All operations in a write request are applied atomically.Write modes
Themode field controls how existing variables are handled:
| Mode | Behavior |
|---|---|
"upsert" | Create new variables and update existing ones. Existing variables not mentioned in entries are unchanged. |
"create_only" | Only create new variables. Returns INVALID_REQUEST if any entry refers to a variable that already exists. |
Request
| Field | Type | Required | Description |
|---|---|---|---|
orgSlug | string | Yes | Org slug |
projectSlug | string | Yes | Project slug |
stageSlug | string | Yes | Stage name |
mode | "upsert" | "create_only" | Yes | How to handle existing variables |
entries | array | No | Variables to create or update |
deletes | string[] | No | Names of variables to delete |
secret variable:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Variable name |
kind | "secret" | Yes | Must be "secret" |
value | string | Yes | Plaintext value |
declaredType | string | No | One of "string", "boolean", "int64", "float", "date", "json" |
ab_roll variable:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Variable name |
kind | "ab_roll" | Yes | Must be "ab_roll" |
valueA | string | Yes | Plaintext value A |
valueB | string | Yes | Plaintext value B |
chance | number | Yes | Probability of returning A (0.0–1.0) |
declaredType | string | No | Declared type for both values |
Response
| Field | Type | Description |
|---|---|---|
created | string[] | Names of variables that were created |
updated | string[] | Names of variables that were updated |
deleted | string[] | Names of variables that were deleted |
requestId | string | Request trace ID |
How writes work
Values are encrypted server-side before being committed to the database. The write goes through a two-phase process:- Prepare — all values are encrypted with the project DEK; storage delta is computed
- Reserve — storage usage is reserved in the billing system
- Commit — encrypted payloads are written to the database
- Settle — storage usage is finalized (or rolled back on failure)
create_only with an existing name) will not encrypt any values or reserve any billing units.
Error codes
| Code | HTTP | When |
|---|---|---|
UNAUTHORIZED | 401 | Invalid or expired token |
INVALID_JSON | 400 | Request body is not valid JSON |
INVALID_REQUEST | 400 | Missing required field, invalid type value, or create_only conflict |
INVALID_ORG_SCOPE | 403 | Token org doesn’t match orgSlug |
USAGE_LIMIT_EXCEEDED | 402 | Storage limit reached on the free plan |
BILLING_UNAVAILABLE | 503 | Billing system temporarily unavailable |

