> ## Documentation Index
> Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Secrets

> Organization-scoped values for sensitive data, managed with the CLI. Every function receives them as environment variables; TypeScript functions can also read them through a typed binding.

Secrets are key-value pairs for sensitive data — API keys, database passwords, signing keys. They are scoped to your organization, stored server-side, and never displayed by the CLI after you set them. Every function receives them; there are two ways to read one.

## Managing secrets

The `secrets` commands take positional arguments:

```bash theme={null}
# Add a secret — or update it, same command
telnyx-edge secrets add STRIPE_API_KEY "sk_live_abc123"
# ✓ Secret 'STRIPE_API_KEY' added successfully

# List secret keys (values are never shown)
telnyx-edge secrets list
# SECRET ID                              SECRET NAME         CREATED AT            UPDATED AT
# ------------                           ----------------    -----------------     -----------------
# 1f4cafea-21ce-4e2b-9740-17d971c3d892   DATABASE_PASSWORD   Jun 12, 2026, 09:41   Jun 12, 2026, 09:41
# 21ef7449-edbb-4248-b869-3d1352563a64   STRIPE_API_KEY      May 28, 2026, 16:20   May 28, 2026, 16:20
# a209b1b3-062c-46f6-a2f2-3b0061751190   JWT_SECRET          May 28, 2026, 16:19   May 28, 2026, 16:19

# Delete a secret
telnyx-edge secrets delete OLD_API_KEY
# ✓ Secret 'OLD_API_KEY' deleted successfully
```

Secrets are injected into function containers at deploy time — after adding or updating one, `telnyx-edge ship` each function that uses it.

## Reading secrets

### As environment variables — every language

Each secret is injected into **all** functions in your organization as an environment variable named after its key. No declaration needed:

<Tabs>
  <Tab title="TypeScript / JavaScript">
    ```ts theme={null}
    const stripeKey = process.env.STRIPE_API_KEY;
    if (!stripeKey) throw new Error("STRIPE_API_KEY not configured");
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os

    stripe_key = os.environ["STRIPE_API_KEY"]
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    stripeKey := os.Getenv("STRIPE_API_KEY")
    if stripeKey == "" {
        log.Fatal("STRIPE_API_KEY not configured")
    }
    ```
  </Tab>

  <Tab title="Quarkus (Java)">
    ```java theme={null}
    String stripeKey = System.getenv("STRIPE_API_KEY");
    ```
  </Tab>
</Tabs>

### Through the typed binding — TypeScript

TypeScript projects can additionally declare a `[[secrets]]` binding in `func.toml` and read the secret through `env.SECRETS`:

```toml theme={null}
# func.toml
[[secrets]]
binding = "STRIPE_KEY"       # the handle your code uses
name    = "STRIPE_API_KEY"   # the key stored with `secrets add`
```

```bash theme={null}
telnyx-edge types   # regenerates telnyx-env.d.ts from the manifest
```

```ts theme={null}
import { env } from "@telnyx/edge-runtime";

const stripeKey = await env.SECRETS.get("STRIPE_KEY"); // get returns Promise<string>
```

Both surfaces read the same store. The binding adds two things: `env.SECRETS.get` accepts only the literal union of declared handles — a typo'd handle fails to compile — and the in-code handle is decoupled from the stored key name, so you can swap `name` in the manifest without touching code. The binding SDK is TypeScript-only today; other runtimes use the injected environment variables.

Enforced when `[[secrets]]` is declared: a **binding** named `SECRETS` and **duplicate `[[secrets]]` handles** are hard errors — `ship` fails. An `[env_vars]` entry named `SECRETS` only **warns** (it shadows the `env.SECRETS` namespace), so rename it. See [Bindings](/docs/edge-compute/runtime/bindings) for how the `env` namespace works.

## Rotating a secret

`add` with an existing key overwrites its value:

```bash theme={null}
telnyx-edge secrets add DATABASE_PASSWORD "new-password"
telnyx-edge ship                # redeploy each function that uses it
curl https://my-func-myorg.telnyxcompute.com/health   # verify
```

## Scoping and local development

Secrets are organization-scoped. There is no per-environment scoping (dev/staging/prod) today — if you need separation, encode it in the key name (`DEV_DATABASE_PASSWORD`, `PROD_DATABASE_PASSWORD`) and pick one in code.

There is no local secrets emulation in the CLI. When running a function locally, export the same names as ordinary environment variables:

```bash theme={null}
STRIPE_API_KEY="sk_test_..." node index.js
```

## Troubleshooting

| Symptom                              | Fix                                                                                                                 |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------- |
| Variable missing in the function     | `telnyx-edge secrets list` to confirm the key exists, then `telnyx-edge ship` — values are injected at deploy time. |
| Stale value                          | `secrets add` again, then `ship`.                                                                                   |
| `env.SECRETS.get` doesn't type-check | Re-run `telnyx-edge types` after editing `[[secrets]]`; pass the `binding` handle, not the `name`.                  |
| CLI rejects the command              | `telnyx-edge auth status`, then `telnyx-edge auth login` if needed.                                                 |

## Next Steps

* [Environment variables](/docs/edge-compute/configuration/environment-variables) — the full picture of what lands in your container's environment
* [Bindings](/docs/edge-compute/runtime/bindings) — the declare → `types` → `env` pattern all bindings share
* [Configuration](/docs/edge-compute/configuration) — `[[secrets]]` and every other manifest key
