API keys
Audience
PLANA staff, integration partners, customers issuing per-workspace API keys for their own automations.
PLANA uses two kinds of API keys:
| Kind | Prefix | Issued by | Used for |
|---|---|---|---|
| Workspace API key | pa_live_… | Tenant admin in BOS → Settings → API keys | Customer automations against their own workspace |
| Service API key | X-API-Key (no prefix) | PLANA platform | Service-to-service calls inside the cluster |
Workspace API keys (pa_live_…)
These are the keys customers create to call PLANA's API from their own scripts. Issued from the BOS UI; bcrypt-hashed in the database; never visible after creation.
Lifecycle
- Tenant admin opens BOS → Settings → API keys → "Create key"
- Names the key (e.g. "Nightly stock sync") and selects scopes
- BOS calls
POST /api/portal/apikeysonpulse-account-api - The API generates a token: prefix
pa_live_+ 32 random bytes base32-encoded (so the token ispa_live_AB7K2…— readable in logs for the prefix, but the body itself is high-entropy) - The API stores only the bcrypt hash of the token in the
api_keytable onpulse_account - The plaintext is shown to the user once, in a copy-to-clipboard field
- Subsequent calls authenticate with the key in the
Authorizationheader:Authorization: Bearer pa_live_…
What the key can do
A workspace API key is scoped to one workspace. The platform identifies which workspace from the key prefix (looked up in api_key) and authorises calls accordingly.
| Scope | What it grants |
|---|---|
dashboard:read | KPIs, cashflow, alerts |
agents:invoke | POST to /api/agents/:id/chat |
banking:read | PSD2 account and transaction read |
webhooks:write | Receive workspace webhooks |
* | Everything — discouraged but available |
A key without an explicit scope set defaults to dashboard:read, the lowest-risk grant.
What the key CANNOT do
- Write to Odoo records directly (no XML-RPC bridge)
- Access another workspace's data (the workspace binding is enforced at the API layer)
- Modify the workspace's own configuration (e.g. team membership)
For those operations the user must log in interactively. API keys are for automation, not for delegating administrative actions.
Revocation
The tenant admin can revoke a key from the same Settings → API keys page: "Revoke" deletes the row in api_key and the key stops working immediately. There is no time-window or grace period.
Audit
Every API call authenticated with a workspace key is logged with the key prefix (not the full token) and the workspace ID. The log is in the PLANA:executions:{workspace} Redis log (visible in BOS → Execution log) and mirrored to Loki for 90-day retention.
Storage
| Where | What |
|---|---|
Database (pulse_account.api_key) | bcrypt(token), name, created_at, last_used_at, revoked_at, workspace_id, scopes |
| Never anywhere else | The plaintext token |
If a customer loses their token, the only option is to revoke and re-issue. We cannot recover it.
Service API keys (X-API-Key)
These are the keys PLANA services use to call each other. They are configured per-service in SOPS and never rotated by a UI.
Inventory
| Calling service | Target service | Header key | SOPS path |
|---|---|---|---|
pulse-account-api | pulse-banking | X-API-Key | pulse_account.banking_api_key |
pulse-account-api | ai-agents | X-API-Key | pulse_account.agents_api_key |
pulse-account-api | pulse-events | X-API-Key | pulse_events.publisher_key |
ai-agents | pulse-data (Neural Business Network) | X-API-Key | ai_agents.pulse_data_key |
pulse-notifications | (callers) | X-API-Key | pulse_notifications.api_key |
pulse-billing (Stripe webhook receiver) | pulse-events | X-API-Key | pulse_events.publisher_key |
saas-orchestrator (historical) | pulse-events | X-API-Key | pulse_events.publisher_key |
The orchestrator entry is historical — the service was deleted in May 2026. The key would only be re-used if we re-add a similar workload.
Rotation
Service keys rotate on a deliberate schedule, not automatically:
- Generate a new key (32 random bytes hex-encoded)
- Update SOPS at the path above
- Update the consumer service's deployment to pick up the new secret (Flux reconciles, the deployment rolls)
- Verify the consumer is using the new key (logs)
- Update the provider service to revoke the old key
- (Optional) Validate by sending a request with the old key and expecting 401
We rotate service keys after any incident that might have exposed them, and on an annual cadence otherwise. The cadence is tracked in the security calendar.
Storage
| Where | What |
|---|---|
SOPS-encrypted YAML (infra/secrets/plana-pulse.enc.yaml) | Plaintext key |
| Vaultwarden mirror | Secondary copy (per the |
| secrets storage policy) | |
| Kubernetes Secret in the namespace of the consuming service | Mounted into the pod as env var |
The plaintext never appears in git in cleartext; only the SOPS-encrypted form is committed.
Authentication layering
API calls are authenticated in layers:
- Layer 1 — Network: NetworkPolicies allow only the right caller pods to reach the target service Service. A leaked key alone cannot reach a service that's blocked at the network level.
- Layer 2 — API key: The target service checks
X-API-Key(for service-to-service) orAuthorization: Bearer pa_live_…(for workspace keys). - Layer 3 — Authorization: For workspace keys, the service further checks the workspace binding and the scope.
A leaked workspace key alone (without network access) is still bounded to one workspace; a leaked service key reaches only services its caller's NetworkPolicy already allows.
Customer-facing best practices
When a customer asks how to use their API key safely:
- Store the key in a secrets manager (HashiCorp Vault, AWS Secrets Manager, doppler, 1Password CLI), not in source code
- Use scope-limited keys — issue one key per automation, scoped to the minimum it needs
- Rotate annually — revoke the old key and issue a new one yearly
- Monitor BOS → Execution log — every API call shows up there with the key prefix; if you see calls you don't recognise, revoke
These are documented for customers at BOS → Settings → API keys.
Where to read more
- Two-factor (TOTP) — second factor for interactive logins
- BOS → Settings → API keys — the customer view
- Security → Secrets management — where keys are stored
- Operations → Alert response — rotation procedure during an incident