Docs

Update variables

PATCH
/variables

Enters, replaces and removes the project's variables for the requested kind. Names not in the body are untouched. Existing deployments keep the values they froze.

Without kind, a plain value is written for both kinds. A secret is written for primary only and removes the name's preview value, so a preview never keeps a plaintext copy; set a preview secret with kind=preview. null removes the name from both.

A bare scalar enters a non-secret value. {"value": …, "secret": true} stores the value encrypted under the project's active secret key, after which it can be referenced but not read back. null removes the name (RFC 7386), which is how several variables are removed in one request; removing a name the project does not hold is a no-op rather than an error.

The body is applied whole or not at all, so a rejected request leaves the project's variables exactly as they were. Writing the same name twice replaces the value rather than duplicating it, which makes a retry safe.

Authorization

oauth2 variable.write
headerAuthorizationBearer <token>

Scope: variable.write

Query Parameters

project_id*string

The unique identifier of the project

Match^[a-zA-Z0-9_-]+$
kind?string

The kind of value to address. Omit it for both kinds.

Value in"primary""preview"

Request Body

application/json
  1. body

The variables to enter, keyed by name. Each is either a bare scalar (a non-secret value), an object stating the secret flag, or null to remove the name.

This is a patch: a name present here is written, replacing whatever the project held under it, and a name absent here is left alone. A name whose value is null is removed (RFC 7386), so one request can enter, replace and remove names together — which is also the way to remove several at once. DELETE /variables/{variable_name} remains the way to remove exactly one name and be told whether it was there.

Removing a name the project does not hold is not an error: a patch states what the project holds afterwards, and that name is already absent. That makes a retry safe, and it is the one place this body differs from DELETE, which answers var.not_found.

The body is applied whole or not at all. Every value is validated, and every secret encrypted, before anything is written, and the writes and removals share one transaction.

Properties1 <= properties
[key: string]?||||

One entry of an update. A bare scalar enters a non-secret value, an object states the flag explicitly, and null removes the name.

The shorthand exists because most variables are not secrets and spelling {"value": …, "secret": false} for each of them is noise. Making a value secret is therefore always deliberate: it cannot happen by writing a plain scalar.

null is the RFC 7386 merge-patch convention: the name is removed, which is what lets one request enter, replace and remove names together. Removing a name the project does not hold is not an error, because a patch states what the project holds afterwards and that name is already absent. DELETE /variables/{variable_name} addresses one name deliberately and still answers var.not_found there.

A null is a removal wherever it appears, so a body built from client state in which an unset field serializes to null removes that variable instead of leaving it alone. A secret removed this way cannot be recovered, since its value reads back nowhere. Send only the names the request means to change.

Response Body

The variables were written. The body is the project's variables read back, so it also carries whatever the write did not touch.

application/json
  1. response

The project's variables, keyed by name, each with its value per kind.

An empty object is an ordinary answer, not an error.

[key: string]?

One variable's values, per kind. A kind with no value is absent.

Properties1 <= properties
Example Request
import { createZitadelClient } from "@zitadel/api/client";const client = createZitadelClient({  baseUrl: process.env.ZITADEL_URL ?? "http://localhost:8080",  token: process.env.ZITADEL_PROJECT_SECRET!, // server-side only});const variables = await client.updateVariables(  {    GOOGLE_CLIENT_ID: "1234567890-abc.apps.googleusercontent.com",    GOOGLE_CLIENT_SECRET: { value: "GOCSPX-example", secret: true },    SESSION_TTL: 3600,    LEGACY_CALLBACK_URL: null,  },  { project_id: "proj_01KWH1P4MYS7F0N9WD3P2E4YM5" },);
Example Response
{  "property1": {    "primary": "string",    "preview": "string"  },  "property2": {    "primary": "string",    "preview": "string"  }}

Was this helpful?