Authentication
Create a workspace API key, scope it to the least authority the job needs, and send it.
Every request to unseal-space is authenticated with a workspace API key sent
as the x-api-key header. The SDK and the CLI attach it for you; only direct
HTTP callers construct the header themselves.
Create a key
Open unseal.space/api-keys and create a named key. Two things are worth getting right at creation time:
- Permissions. A key carries an explicit permission map. Anything outside it
fails with
app.FORBIDDEN(403). Start from a preset and remove what you do not need. - Expiry. Keys can expire in 30, 90, or 365 days, or never.
The secret is shown once. Store it in your secret manager; a lost key is rotated, not recovered.
API keys cannot create, rotate, revoke, or widen other API keys. That is deliberate — a leaked key cannot escalate itself. Managing keys always requires a browser session.
Permission presets
| Preset | Grants | Use it for |
|---|---|---|
| build | projects:read,write · preview:read · environment:read,write · messages:read,write · attachments:write | An agent that creates projects and iterates on them |
| publish | projects:read · environment:read · deployments:read,write | A CI job that only ships what already exists |
| domain | projects:read · registeredDomains:* · connectedDomains:* | Domain purchase and routing automation |
Two capabilities are in no preset and must be granted deliberately:
projects:restore— rewrites a project's working tree back to an older version. Destructive to in-progress work.registeredDomains:purchase— spends real money.
Send it
import { createUnsealSpaceClient } from "@unseal-ai/unseal-space-sdk";
const client = createUnsealSpaceClient({
baseUrl: "https://api.unseal.space",
apiKey: process.env.UNSEAL_SPACE_API_KEY!,
});Failure modes
| Code | Status | What happened |
|---|---|---|
app.UNAUTHORIZED | 401 | Header missing, or the key is revoked or expired |
app.FORBIDDEN | 403 | The key is valid but lacks the permission for the call |
A 403 is a permissions problem, never a routing one — do not retry it with a different endpoint. Widen the key on the API Keys page, or use a key that already has the capability.