Authentication
API key-based authentication with multi-tenancy and org-scoped isolation.
Overview
GaaS uses API keys for authentication. Every request to the governance API (except pre-auth endpoints) must include an X-API-Key header. API keys are bound to your organization and provide automatic multi-tenant isolation across all resources.
Obtaining an API Key
The fastest way to get an API key is through the quickstart endpoint:
POST https://api.gaas.is/v1/onboarding/quickstart
Content-Type: application/json
{
"org_name": "Your Company",
"email": "admin@yourcompany.com",
"description": "Brief description of your use case"
}
All three fields are required strings. The endpoint provisions an organization, generates a governance membrane in shadow mode, and returns an API key in a single call.
The response includes your API key in the api_key field:
{
"membrane_id": "mem_abc123...",
"membrane_status": "shadow",
"org_id": "org_abc123",
"api_key": "gsk_live_org_a1b2c3d4e5f6...",
"key_id": "key_abc123",
"quickstart_snippet": "from gaas_sdk import GaaSClient ...",
"next_steps": [
"Submit your first intent with POST /v1/intents",
"Review shadow decisions in the dashboard",
"Activate live mode when ready"
]
}
Using Your API Key
Include your API key in the X-API-Key header on every request:
Python (gaas_sdk)
from gaas_sdk import GaaSClient
async with GaaSClient(
"https://api.gaas.is",
headers={"X-API-Key": "gsk_live_org_a1b2c3d4e5f6..."},
) as client:
response = await client.submit_intent(intent)
TypeScript (@gaas/sdk)
import { GaaSClient } from '@gaas/sdk';
const client = new GaaSClient({
baseUrl: 'https://api.gaas.is',
headers: { 'X-API-Key': 'gsk_live_org_a1b2c3d4e5f6...' },
});
const response = await client.submitIntent(intent);
Java (com.gaas.sdk)
import com.gaas.sdk.GaaSClient;
GaaSClient client = GaaSClient.builder()
.baseUrl("https://api.gaas.is")
.apiKey("gsk_live_org_a1b2c3d4e5f6...")
.build();
GaaSResponse response = client.submitIntent(intent);
cURL
curl -X POST https://api.gaas.is/v1/intents \
-H "X-API-Key: gsk_live_org_a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{"intent": {...}}'
API Key Format
GaaS API keys follow this format:
gsk_<environment>_<scope>_<random>
| Component | Description | Example |
|---|---|---|
gsk_ |
Prefix (GaaS Key) | gsk_ |
environment |
Deployment environment | live, shadow, test |
scope |
Access scope | org (most common) |
random |
Unique identifier (32+ chars) | a1b2c3d4e5f6... |
Example: gsk_live_org_a1b2c3d4e5f6g7h8i9j0...
Multi-Tenancy
Every API key is bound to an organization ID (org_id). All resources—decisions, escalations, policies, audit records, webhooks, and more—are automatically scoped to your organization.
This means:
- You can only access data for your own organization
- Cross-organization queries are automatically blocked
- Audit trails, learning data, and onboarding records are isolated by
org_id - Shadow mode, quotas, and billing are org-scoped
org_id is automatically extracted from your API key and injected into the request context. You don't need to pass it manually—it's handled transparently by the middleware.
Pre-Auth Endpoints
Some endpoints do not require authentication (marked pre-auth in the API reference). These are typically public-facing endpoints for initial onboarding, email verification, or unsubscribe flows:
POST /v1/onboarding/quickstart— Provision your first API keyPOST /v1/waitlist/join— Join the waitlistPOST /v1/waitlist/verify— Verify email addressPOST /v1/waitlist/unsubscribe— Unsubscribe from waitlistGET /v1/drip/unsubscribe— Unsubscribe from drip campaignsGET /v1/subprocessor/object— GDPR objection form (token-gated)POST /v1/subprocessor/object— Submit objectionPOST /webhooks/resend— Email provider webhook receiver
All other endpoints require a valid X-API-Key header.
Key Rotation & Revocation
Atomic Rotation (Recommended)
Use the atomic rotation endpoint to create a new key and revoke the old one in a single transaction — zero risk of key leakage or misconfigured windows:
POST https://api.gaas.is/v1/api-keys/{key_id}/rotate
X-API-Key: your_current_api_key
The response includes the new key immediately. The old key is revoked atomically — no overlap window to manage.
{
"key_id": "key_new_abc123...",
"api_key": "gsk_live_org_newkey...",
"expires_at": "2026-05-19T00:00:00Z",
"rotated_from": "key_old_xyz789..."
}
Manual Rotation
Alternatively, rotate manually for more control over the transition:
- Generate a new key via the dashboard or
POST /v1/api-keys(admin only) - Update your application's environment variables to use the new key
- Deploy the updated configuration
- Revoke the old key via
DELETE /v1/api-keys/{key_id}
Key Expiration & Lifetime
API keys support automatic expiration. When a key's expires_at timestamp is reached, it is rejected at the auth layer — no manual revocation needed.
- Configurable max lifetime — keys cannot be created with a lifetime exceeding
GAAS_API_KEY_MAX_LIFETIME_DAYS(default: 90 days) - Expired keys return 401 — the response includes an
X-GaaS-Key-Expired: trueheader for easy detection - Rotate before expiry — use the atomic rotation endpoint to seamlessly replace a key before it expires
Best Practices
- Never hardcode API keys in source code. Use environment variables (
GAAS_API_KEY) or a secrets manager (AWS Secrets Manager, HashiCorp Vault). - Use separate keys for development, staging, and production environments.
- Rotate keys regularly (every 90 days recommended) or immediately if compromised.
- Monitor key usage via the dashboard to detect anomalies (unexpected IP addresses, traffic spikes).
- Restrict access to key storage systems using IAM roles or RBAC.
- Revoke unused keys promptly to minimize attack surface.
Troubleshooting
401 Unauthorized
Cause: Missing or invalid API key.
Solution: Verify that the X-API-Key header is present and matches a valid, non-revoked key.
403 Forbidden
Cause: API key is valid, but you lack permissions for the requested operation (e.g., admin-only endpoint).
Solution: Check your user role in the dashboard. Contact your organization admin to request elevated permissions.
401 Unauthorized (Expired Key)
Cause: Your API key has passed its expires_at timestamp.
Solution: Rotate the key using POST /v1/api-keys/{key_id}/rotate or provision a new key. Check the X-GaaS-Key-Expired: true response header to confirm expiration is the cause.
Open Mode Not Working
Cause: API keys or GAAS_API_KEYS env var are configured, disabling open mode.
Solution: Remove all API keys and unset GAAS_API_KEYS to enable open mode (local development only).
Related Pages
- Getting Started — Onboard and obtain your first API key
- Billing & Quotas — Usage limits and enforcement
- Rate Limits — Per-endpoint request limits
- API Reference — Complete endpoint documentation