Company secrets
Learn about encrypted credentials for companies, scoped per extension, accessed via Secrets.get / set / delete.
Use secrets for anything a company admin shouldn’t see in plaintext: API keys, webhook signing secrets, OAuth tokens. Secrets are encrypted at rest and never returned to the Backfill read APIs.
Signatures
Secrets.get(name: string): string | null;
Secrets.set(name: string, value: string): void;
Secrets.delete(name: string): boolean;
Secrets.has(name: string): boolean;
Secrets.list(): string[];
Declaring access
permissions: {
secrets: {
stripe_api_key: ["read"],
webhook_secret: ["read"],
},
}
The verb model matches entities: "read" and "write". A hook with only "read" cannot call Secrets.set(...).
Secret names must match ^[a-z][a-z0-9_]{0,62}$ — lowercase, starts with a letter, underscores allowed.
Reading
const apiKey = Secrets.get("stripe_api_key");
if (!apiKey) {
throw new Error("stripe_api_key is not configured");
}
Secrets.get returns null if the secret hasn’t been set. Never log the value.
Setting from inside the extension
If your extension grants "write" on a secret, you can rotate it from a hook, job, or route:
Secrets.set("oauth_refresh_token", newToken);
Most extensions only need "read". The dashboard / CLI is the canonical place to set secrets.
Secrets via connector settings schema
For connectors, the JSON Schema in connection.settingsSchema can mark fields as x-secret: true:
api_key: {
type: "string",
title: "Secret API key",
"x-secret": true,
"x-placeholder": "sk_live_...",
}
The dashboard renders the field as a password input and stores the value in the secret store keyed by the field name.
Constraints
- No environment variables. There is no
process.env. - No remote secret stores (Vault, AWS Secrets Manager). The platform’s secret store is the only one.
- Reads are synchronous and idempotent within a script.