Authentication
Every paid request — REST, MCP, webhooks — carries a single API key as a bearer token. Keys are scoped to the tenant that issued them, not the user, so rotating a key never breaks a teammate.
API keys
Keys look like th_live_d3a7...8c41 — a fixed th_live_ prefix plus a high-entropy random tail. The secret is shown once, at issue time. Store it in your secrets manager immediately; we retain only an Argon2id hash plus the last 4 characters.
# Sign in to the web UI -> Team -> API keys -> "New key"# Or via the management API (Team-tier admins): curl -X POST https://api.terminal.house/v1/team/api-keys \ -H "Authorization: Bearer th_live_d3a7...8c41" \ -H "Content-Type: application/json" \ -d '{ "label": "production · 2026-Q2" }' # Response:# {# "id": "01H9X...",# "label": "production · 2026-Q2",# "last4": "8c41",# "secret": "th_live_d3a7...8c41", <- shown ONCE; store it now# "member_id": "01H8...",# "revoked": false# }
You can also issue + revoke keys interactively at terminal.house/api-keys.
Bearer header
Pass the key on every authenticated request as a Authorization: Bearer header. Keys in the URL, query string, or request body are rejected with 401.
curl https://api.terminal.house/v1/leads \ -H "Authorization: Bearer th_live_d3a7...8c41"
Public endpoints that don't require auth (/v1/health, /v1/public/contact) ignore the header if present.
Tier-based feature gating
The same key works across every surface your tier unlocks. Tier mismatch returns 403 with an upgrade-prompt URL — see Errors.
| Tier | REST | MCP | Webhooks | CSV | Seats |
|---|---|---|---|---|---|
| Starter | ✓ | — | — | — | 1 |
| Operator | ✓ | ✓ | ✓ | ✓ | 1 |
| Team | ✓ | ✓ | ✓ | ✓ | up to 5 |
| Custom | ✓ | ✓ | ✓ | ✓ | 6+ |
MCP-side auth
MCP clients (Claude Desktop, Cursor, Windsurf, etc.) persist the key in their own config file. We recommend env-var indirection so the secret never lives in a checked-in config:
{ "mcpServers": { "terminal.house": { "url": "https://mcp.terminal.house/mcp", "env": { "TERMINAL_HOUSE_API_KEY": "${TERMINAL_HOUSE_API_KEY}" } } }}
The full per-client setup walkthrough lives in MCP server documentation.
Rotation + revocation
We recommend rotating keys every 90 days. There's no forced expiry (we won't silently invalidate a working key), but the web UI shows a soft reminder when a key crosses 90 days old.
Rotation is two-step: issue a new key, deploy it, then revoke the old one. Revocation is immediate — the next request with the revoked key gets 401.
curl -X DELETE https://api.terminal.house/v1/team/api-keys/01H9X... \ -H "Authorization: Bearer th_live_d3a7...8c41" # Response: 204 No Content
If a key may have leaked
Revoke immediately. Don't wait for the rotation window. If you suspect a broader compromise (e.g. the key was in a commit pushed to a public repo), revoke every active key on the tenant and rotate webhook signing secrets too. Contact security@terminal.house if you need help auditing what was accessed.