Store encrypted API keys and credentials.
Overview
Environment secrets are encrypted key-value pairs injected into your agent's runtime. Use them for API keys, tokens, and credentials you already have.
Adding a secret
Via the web app
From the secrets tab:
- Open Vaults in the sidebar, select the default vault, and open the secrets tab (
/vaults?tab=secrets) - Click add secret
- Enter a key (e.g.,
OPENAI_API_KEY) and value - Click save
When an app is missing a required secret, the workspace setup dialog lists each key with add. add opens this tab with the add dialog prefilled and returns you to the app after save (see How they work with apps).
From the credentials tab, add credential → environment variable runs the same flow. For an API key that belongs to a provider in the catalog, use add credential → API key. Picking a provider links the secret to that provider's credential (BYOK), and a who can use it selector sets the credential scope. When you type a provider name we do not list yet, the key is still saved as a team secret (optionally with a website for the logo) — it is not the same as registering an OAuth app; for OAuth to a new service, use connect an account → not listed? add your own OAuth provider (auth providers).
If you add a secret on the secrets tab (or with belt secrets set) using a key name that belongs to exactly one catalog API key provider — the same name as that provider's standard API key environment variable — the platform links it to your team's credential for that provider automatically. You do not need to pick the provider in the UI. Custom key names, names shared by more than one provider, and OAuth app credential names (for example your own X_CLIENT_ID / X_CLIENT_SECRET for BYOK) stay plain environment secrets; configure BYOK OAuth through add credential instead.
add credential and add secret require the workspace admin role. Other members can see the list of secrets with masked values. They cannot reveal, create, update, or delete them.
Via CLI
1# Set a secret (creates or updates; prompts for the value without echo)2belt secrets set OPENAI_API_KEY34# Pipe the value in scripts, with a description5printf %s "$OPENAI_API_KEY" | belt secrets set OPENAI_API_KEY -d "For GPT-4 API calls"67# Save as a provider's credential in one step (same as POST /secrets with provider)8belt secrets set GRAFANA_API_KEY --provider grafana9belt secrets set ACME_API_KEY --value-stdin --provider acme --provider-name "Acme CRM" --provider-website acme.com < key.txt1011# Link an existing vault key to a provider without changing the value12belt secrets attach GRAFANA_URL grafana13belt secrets detach GRAFANA_API_KEY1415# List all secrets16belt secrets list1718# Get a specific secret (shows masked value)19belt secrets get OPENAI_API_KEY2021# Delete a secret22belt secrets delete OPENAI_API_KEYUse --as user|team|org (or --team for --as team) on belt secrets set --provider … and belt secrets attach to set connection scope. Updating an existing key with --provider updates the value, then attaches it when the key was already in the vault.
For catalog API key providers, belt credentials connect <provider> prompts for each declared key (masked when the provider marks them sensitive), saves them through the secrets path, and reports connected when the server does. In CI or scripts, run the printed belt secrets set <KEY> --value-stdin --provider <provider> < value-file lines instead.
Your agents can now access it via environment variables:
1import os2api_key = os.environ["OPENAI_API_KEY"]Security
| Feature | Benefit |
|---|---|
| Encrypted at rest | AES-256-GCM encryption |
| Never logged | Not exposed in task outputs or logs |
| Workspace scoped | Other workspaces cannot access your secrets |
| Runtime only | Injected only when apps run, not stored in code |
| Selective injection | Only apps that declare the secret receive it |
Using in apps
Apps declare which secrets they need:
1# inf.yml2secrets:3 - key: OPENAI_API_KEY4 description: For GPT-4 API calls56 - key: DATABASE_URL7 description: PostgreSQL connection string8 optional: trueRequired secrets must be set before the app can run.
Optional secrets won't block execution if missing.
Best practices
Use descriptive names
1✓ OPENAI_API_KEY2✓ MY_STRIPE_SECRET_KEY3✓ AWS_ACCESS_KEY_ID45✗ KEY16✗ TOKEN7✗ SECRETSome names are reserved for platform settings (for example STRIPE_SECRET_KEY, SMTP_PASSWORD). Use a team-specific prefix when the obvious name is reserved.
Don't commit secrets
Never put secrets in:
- Version control
- App code
- Configuration files
Store them in vaults → secrets instead.
Rotate regularly
- Generate a new key in the external service
- Update the secret in vaults → secrets
- Revoke the old key
No app changes needed.
Use separate keys per environment
If you have staging and production:
- Use different API keys for each
- Set different secrets per workspace/environment
Common secrets
| Secret | Service | Description |
|---|---|---|
OPENAI_API_KEY | OpenAI | GPT-4, DALL-E, Whisper |
ANTHROPIC_API_KEY | Anthropic | Claude models |
REPLICATE_API_TOKEN | Replicate | ML model hosting |
HUGGINGFACE_TOKEN | Hugging Face | Model downloads |
AWS_ACCESS_KEY_ID | AWS | S3, Lambda, etc. |
AWS_SECRET_ACCESS_KEY | AWS | (paired with above) |
MY_STRIPE_SECRET_KEY (not STRIPE_SECRET_KEY — reserved) | Stripe | Payment processing |
SENDGRID_API_KEY | SendGrid | Email delivery |
TWILIO_AUTH_TOKEN | Twilio | SMS, voice |
Secrets vs Credentials
| Feature | Secrets | Credentials |
|---|---|---|
| Setup | You provide the key | OAuth flow or service account |
| Management | Manual rotation | Auto token refresh |
| Best for | APIs with static keys | OAuth services (Google, X.com) |
| Examples | OpenAI, Stripe, AWS | Gmail, Google Sheets, Twitter |
Use secrets when you have an API key.
Use credentials for OAuth services where we handle token management.
Troubleshooting
"Secret not found"
- Check the exact key name (case-sensitive)
- Verify the secret is set in vaults → secrets
- Make sure the app declares the secret in requirements
"Permission denied"
- Secrets are workspace-scoped, so you need access to the workspace
- Check you're in the correct workspace:
belt me(look for a workspace override message) - Switch workspaces with
belt auth switchif secrets were created in a different workspace
App not receiving secret
- The app must declare the secret in
requirements.secrets - Only declared secrets are injected for security