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

# Securely store and use API keys and secrets in Paige

> Secrets are encrypted key-value pairs stored per project. Add API keys and credentials in the dashboard, then access them in bot code via process.env.

Secrets are how you store sensitive values — API keys, credentials, tokens — that your bot needs at runtime. Each secret is encrypted at rest and scoped to a single project. When your bot code runs, Paige decrypts the secrets for that project and injects them as environment variables. Your code reads them with `process.env.SECRET_NAME`, just like any other environment variable.

## How secrets work

Secrets are stored as encrypted key-value pairs. The key becomes the environment variable name in your bot code. The value is the sensitive string you want to protect — an API key, a bearer token, a database password.

Secrets are:

* **Encrypted at rest** — stored in an encrypted form; the plaintext value is only available at runtime when your bot executes
* **Per-project** — a secret in one project is never accessible from another
* **Not logged** — Paige does not include secret values in execution logs or error messages

## Adding a secret

Navigate to your project's **Settings** and open the **Secrets** section. Enter a key name and the secret value, then save.

Key naming rules:

* Use uppercase letters, numbers, and underscores (e.g. `OPENAI_API_KEY`, `CRM_API_TOKEN`)
* Keys are case-sensitive
* No spaces or special characters other than underscores

<Note>
  After saving, the secret value is masked in the dashboard. You can overwrite a secret by saving a new value for the same key, or delete it entirely. You cannot read back the stored value once it has been saved.
</Note>

## Accessing secrets in bot code

Once a secret is saved, access it in your bot code using `process.env`:

```javascript theme={null}
// Access a stored secret by its key name
const openAiKey = process.env.OPENAI_API_KEY;
const crmToken = process.env.CRM_API_TOKEN;
const webhookSecret = process.env.WEBHOOK_SECRET;
```

You can reference secrets anywhere in your bot code — in service files, route handlers, or utility functions.

```javascript theme={null}
// Example: initialise the OpenAI client using a stored secret
const OpenAI = require("openai");

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});
```

```javascript theme={null}
// Example: authenticate a third-party API call
const response = await fetch("https://api.example-crm.com/contacts", {
  headers: {
    Authorization: `Bearer ${process.env.CRM_API_TOKEN}`,
  },
});
```

## Managing secrets

<Tabs>
  <Tab title="List secrets">
    To see all secret keys stored for your project (not their values), navigate to **Settings → Secrets** in your project dashboard. The list shows key names and the date each secret was last updated.
  </Tab>

  <Tab title="Update a secret">
    To update the value of an existing secret, navigate to **Settings → Secrets**, find the key you want to update, and enter the new value. Saving overwrites the previous value immediately.
  </Tab>

  <Tab title="Delete a secret">
    To delete a secret, navigate to **Settings → Secrets**, find the key, and click **Delete**. Once deleted, any bot code that references `process.env.KEY_NAME` will receive `undefined` until you add the key back.
  </Tab>
</Tabs>

<Warning>
  Deleting a secret that your bot code depends on will cause runtime errors. Make sure to update or remove the references in your bot code before deleting a secret.
</Warning>

## Common use cases

<AccordionGroup>
  <Accordion title="OpenAI API key">
    If your bot uses the AI template, it requires an OpenAI API key for generating responses and transcribing voice notes.

    Add a secret with key `OPENAI_API_KEY` and your OpenAI key as the value. The template reads it automatically via `process.env.OPENAI_API_KEY`.
  </Accordion>

  <Accordion title="CRM API credentials">
    If your bot looks up or creates contacts in a CRM (HubSpot, Zoho, Salesforce, etc.), store the API key or OAuth token as a secret.

    For example, add `HUBSPOT_API_KEY` and reference it in your integration service:

    ```javascript theme={null}
    const hubspot = require("@hubspot/api-client");
    const client = new hubspot.Client({ accessToken: process.env.HUBSPOT_API_KEY });
    ```
  </Accordion>

  <Accordion title="Third-party service credentials">
    Any external service your bot calls — payment processors, SMS gateways, scheduling APIs, email services — should have their credentials stored as secrets rather than hardcoded in your bot code.

    Common examples:

    * `STRIPE_SECRET_KEY` for payment processing
    * `SENDGRID_API_KEY` for email sending
    * `GOOGLE_MAPS_API_KEY` for location lookups
  </Accordion>

  <Accordion title="Webhook verification tokens">
    If your bot calls an external service that sends webhooks back to you, store the shared secret or verification token used to validate incoming requests.

    ```javascript theme={null}
    const incomingSignature = req.headers["x-webhook-signature"];
    const expectedSignature = crypto
      .createHmac("sha256", process.env.WEBHOOK_SECRET)
      .update(req.rawBody)
      .digest("hex");

    if (incomingSignature !== expectedSignature) {
      return res.sendStatus(401);
    }
    ```
  </Accordion>
</AccordionGroup>

## Security notes

* **Do not hardcode sensitive values** in your bot code files. Anyone with access to your project can read the code; secrets in `process.env` are not exposed in the code editor.
* **Rotate secrets regularly** for high-sensitivity credentials. Update the value in **Settings → Secrets** and your bot picks up the new value on the next execution.
* **Secrets are not available in flow JSON** files. Flows run on Meta's infrastructure, not Paige's runtime. If a flow needs a dynamic value, pass it as a flow action payload from your bot code instead.
