# set_secrets

Source: https://modulify.ai/docs/api/secrets/set-secrets

Creates, replaces and deletes environment variables on a site in one call, which is how a whole .env file is applied.

- Title: Set several environment variables at once
- Scope: `config:write`
- Access: Destructive
- Endpoint: `POST /v1/set_secrets`

Everything in `secrets` is upserted and everything named in `deleteKeys` is removed. The 200 variable ceiling is checked against the result of both, so one call can swap a full set.

Each entry can carry `IsPublic`, which works like `isPublic` on `set_secret`: true stores the value unencrypted and false stores it encrypted. Leave it out and a key starting with `NEXT_PUBLIC_` is stored unencrypted while every other key is stored encrypted, so rewriting an existing public variable without `IsPublic` can flip it to encrypted if its name lacks that prefix.

Locked keys, reserved names and names that cannot be sanitized are skipped rather than failing the call, and listed in `skipped`. The response carries `upserted` and `deleted`, which are counts, `skipped`, and `secrets`, the site's whole variable list after the change with a value only for the unencrypted ones. `skipped` names only what it refused to write: a deletion of a locked, reserved or unknown key is ignored without a mention, so compare `deleted` with the number of names you sent in `deleteKeys` to tell whether one was refused.

Like `set_secret`, it pushes the new set to the running preview straight away, and the published site keeps the old values until it is published again. See [Secrets](https://modulify.ai/docs/data/secrets).

## Request

Call it with a `POST` to `https://api.modulify.ai/v1/set_secrets`, sending the inputs below as a JSON object. The token needs the `config:write` scope.

> **Warning**
>
> This method is marked destructive: it deletes or overwrites data. Check the inputs before you call it, and send an [Idempotency-Key](https://modulify.ai/docs/api/idempotency) header whenever you might retry it.

```bash
curl -X POST https://api.modulify.ai/v1/set_secrets \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"projectId":"PROJECT_ID"}'
```

Over MCP, the same method is the [set_secrets tool](https://modulify.ai/docs/mcp/secrets/set-secrets).

## Inputs

| Input | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string | Yes | The site id. |
| `secrets` | array of objects | No | The variables to create or replace, each with `Key`, the variable name, `Value`, the value to store, and an optional `IsPublic`: true stores the value unencrypted so it can be read back without a reveal, false stores it encrypted, and leaving it out decides by the `NEXT_PUBLIC_` prefix. It is about storage, not browser exposure, and never true for a credential. A key that already exists is overwritten with no warning. |
| `deleteKeys` | array of strings | No | Variable names to delete, by name rather than by id. Deleting one the running site reads breaks it. |

## Response

Every call answers with the [JSON envelope](https://modulify.ai/docs/api/requests-and-responses#the-response) of `success`, `message`, `data`, `code` and `version`. `data` holds the result described above, and on a method that returns a total, `count` carries it. The [response headers](https://modulify.ai/docs/api/requests-and-responses#headers-on-every-method-call) carry the call's `X-Request-Id` and what is left of your per-minute budget in `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. [Errors](https://modulify.ai/docs/api/errors) explains every status code a call can answer with.