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

# Secrets

> Manage encrypted environment variables: three ways to configure them, access with ctx.env, prefix restrictions, and CI usage.

## What are secrets?

Secrets are encrypted environment variables that you access at runtime through `ctx.env`. Use them for API keys, database URLs, external service tokens, and any sensitive values.

## Configure secrets

You have three ways to configure secrets with the CLI:

<Tabs>
  <Tab title="Inline">
    Pass `KEY=VALUE` pairs directly:

    ```bash theme={null}
    jelou secrets set query-customer CRM_API_KEY=sk_test_EXAMPLE JELOU_API_KEY=jfn_pat_EXAMPLE
    # ✓ Set 2 secrets
    ```
  </Tab>

  <Tab title=".env file">
    Import from a `.env` file:

    ```bash theme={null}
    jelou secrets set query-customer --from-env .env.production
    ```

    The file follows the standard format:

    ```bash .env.production theme={null}
    CRM_API_KEY=sk_test_EXAMPLE
    JELOU_API_KEY=jfn_pat_EXAMPLE
    DATABASE_URL=postgres://user:pass@host:5432/db
    ```

    Empty lines and comments (`#`) are ignored.
  </Tab>

  <Tab title="Interactive">
    Without arguments, the CLI guides you step by step:

    ```bash theme={null}
    jelou secrets set query-customer
    # ? Secret key: CRM_API_KEY
    # ? Secret value: ****
    # ? Add another secret? (y/N) y
    # ? Secret key: JELOU_API_KEY
    # ? Secret value: ****
    # ? Add another secret? (y/N) n
    # ✓ Set 2 secrets
    ```

    Values are masked during input.
  </Tab>
</Tabs>

Keys must be `UPPER_SNAKE_CASE` (pattern: `^[A-Z][A-Z0-9_]*$`).

## Access secrets in your function

Use `ctx.env` inside the handler:

```typescript index.ts theme={null}
import { define, z } from "@jelou/functions";

export default define({
  name: "send-whatsapp",
  description: "Sends a WhatsApp message using the Jelou API",
  input: z.object({
    phone: z.string().min(10),
    message: z.string().min(1),
  }),
  handler: async (input, ctx) => {
    const apiKey = ctx.env.get("JELOU_API_KEY");
    const botId = ctx.env.get("BOT_ID");

    if (!apiKey) {
      ctx.log("Error: JELOU_API_KEY not configured");
      return { sent: false, error: "Missing API key" };
    }

    const res = await fetch("https://api.jelou.ai/v1/messages/send", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${apiKey}`,
      },
      body: JSON.stringify({
        botId,
        phone: input.phone,
        message: input.message,
      }),
    });

    return { sent: res.ok, status: res.status };
  },
});
```

### `ctx.env` methods

| Method               | Returns                  | Description                   |
| -------------------- | ------------------------ | ----------------------------- |
| `ctx.env.get("KEY")` | `string \| undefined`    | Gets the value of a secret    |
| `ctx.env.has("KEY")` | `boolean`                | Checks if a secret exists     |
| `ctx.env.toObject()` | `Record<string, string>` | Gets all secrets as an object |

## Blocked variables

Internal platform variables with the `__FN_` prefix are blocked. Calling `ctx.env.get("__FN_COMPANY_ID")` returns `undefined`.

## Local development

In local development, the `jelou functions dev` server loads secrets from your `.env` file:

```bash .env theme={null}
CRM_API_KEY=sk-test-local123
JELOU_API_KEY=jfn_pat_test_local
DATABASE_URL=postgres://localhost:5432/mydb
```

You can specify a different file:

```bash theme={null}
jelou functions dev --env .env.local
```

<Warning>
  Never commit your `.env` file to the repository. `jelou functions init` adds it automatically to `.gitignore`.
</Warning>

## List and delete secrets

```bash theme={null}
jelou secrets list query-customer
# ▸ Key              Updated
# ▸ CRM_API_KEY      2 hours ago
# ▸ JELOU_API_KEY    3 days ago

jelou secrets delete query-customer CRM_API_KEY
# ✓ Deleted CRM_API_KEY
```

## Secrets in CI/CD

In CI pipelines, use system environment variables to inject secrets:

```yaml deploy.yml theme={null}
- name: Configure secrets and deploy
  env:
    JELOU_TOKEN: ${{ secrets.JELOU_TOKEN }}
  run: |
    jelou secrets set query-customer \
      CRM_API_KEY=${{ secrets.CRM_API_KEY }} \
      JELOU_API_KEY=${{ secrets.JELOU_API_KEY }}
    jelou functions deploy --no-confirm
```
