API Keys & Authentication
How requests to Outpost are authenticated and scoped.
Every request to Outpost (except the public opt-out page) is authenticated with an API key sent in the x-api-key header.
In the dashboard: keys are issued and revoked from a project's API Access section, see Managing Tenants & Projects.
How they relate
API keys are owned by projects, and the tenant/project a key belongs to is stamped onto every message it sends - which is how messages, stats, and webhooks all end up correctly scoped.
Two kinds of keys
| Admin key | Tenant key | |
|---|---|---|
| Scope | Entire system | One tenant + one project |
| Created via | By hand (deliberately no API) | POST /projects/:projectId/api-keys |
Can specify tenantId/projectId in requests | Yes | No - returns 403 |
| Typical user | Outpost dashboard, operators | Downstream services |
Key facts
The plaintext key is shown exactly once. Creating a key returns plainApiKey a single time. Outpost stores only a SHA-256 hash - if the plaintext is lost, create a new key. Keys look like outpost-<token>, so they're recognizable in config files without revealing their scope.
Validation is a single fast lookup. For a tenant key to be valid: the key must exist, be active, not be expired, and both its tenant and project must be active. Tenant/project status is denormalized onto the key record (tenantIsActive, projectIsActive), so disabling a tenant takes effect immediately without adding database reads to the authentication hot path.
Failures are distinct. An invalid/expired/deactivated key returns 401; a valid key used on an endpoint its role doesn't allow returns 403.
Keys can expire. An optional expiresAt can be set at creation. Expired keys remain in the system but stop working.
Limits: a project can have at most 10 API keys.
The one unauthenticated surface
The public messaging status page (GET/POST /o/:token) is intentionally unauthenticated so message recipients can manage their opt-out state from a link. It is rate-limited and tokens are unguessable - see Phones & Opt-Out.
API reference
GET /v1/projects/:projectId/api-keys- list a project's keys (hashes only)POST /v1/projects/:projectId/api-keys- create a key (plaintext returned once)DELETE /v1/projects/:projectId/api-keys/:keyId- revoke a key
Calling from TypeScript? See Generating a Typed Client.