Authentication
Horizon uses two distinct authentication mechanisms. Standard API operations use scoped API keys, while administrative operations use an admin secret. Both are passed as HTTP headers on every request.
API Key Authentication
Section titled “API Key Authentication”Most API endpoints require an API key passed in the x-api-key header. API keys are created through the Admin API Keys endpoints or from the Settings > API Keys page in the dashboard.
GET /api/conversations HTTP/1.1Host: api.horizonplatform.aix-api-key: hz_live_abc123def456...Each API key has the following properties:
| Property | Description |
|---|---|
client_name | A human-readable label identifying the key’s owner or purpose. |
scopes | An array of strings defining which skill categories the key can access. |
rate_limit | Maximum requests per minute. Defaults to 100. |
expires_at | Optional expiration timestamp. The key is rejected after this time. |
enabled | Whether the key is currently active. Revoked keys have this set to false. |
Scopes
Section titled “Scopes”Scopes control which skill categories an API key is authorized to execute. When you call a skill execution endpoint like POST /api/quickbooks/v1/profit-and-loss-report, Horizon checks that the API key includes a scope matching the skill’s category (e.g., quickbooks).
Common scope values:
quickbooks— Access to QuickBooks skillssage-intacct— Access to Sage Intacct skillsweb— Access to web skillsplatform— Access to platform management skillsconversations— Access to conversation endpointsmemory— Access to agent memory endpointsscheduler— Access to scheduled job endpointswebhooks— Access to webhook management endpoints
A key can hold multiple scopes:
{ "client_name": "backend-service", "scopes": ["quickbooks", "conversations", "memory"]}Example: Using an API Key
Section titled “Example: Using an API Key”curl -X GET https://api.horizonplatform.ai/api/conversations \ -H "x-api-key: hz_live_abc123def456"const response = await fetch('https://api.horizonplatform.ai/api/conversations', { method: 'GET', headers: { 'x-api-key': 'hz_live_abc123def456', },});
const conversations = await response.json();import requests
response = requests.get( 'https://api.horizonplatform.ai/api/conversations', headers={'x-api-key': 'hz_live_abc123def456'})
conversations = response.json()Admin Secret Authentication
Section titled “Admin Secret Authentication”Administrative endpoints under the /admin prefix require the admin secret instead of an API key. The admin secret can be passed in one of two ways:
Option 1: Authorization header (recommended)
POST /admin/api-keys HTTP/1.1Host: api.horizonplatform.aiAuthorization: Bearer your-admin-secret-hereContent-Type: application/jsonOption 2: x-admin-secret header
POST /admin/api-keys HTTP/1.1Host: api.horizonplatform.aix-admin-secret: your-admin-secret-hereContent-Type: application/jsonAdmin endpoints include:
POST /admin/api-keys— Create a new API keyGET /admin/api-keys— List all API keysDELETE /admin/api-keys/:id— Revoke an API key
Example: Admin Authentication
Section titled “Example: Admin Authentication”curl -X GET https://api.horizonplatform.ai/admin/api-keys \ -H "Authorization: Bearer your-admin-secret-here"const response = await fetch('https://api.horizonplatform.ai/admin/api-keys', { method: 'GET', headers: { 'Authorization': 'Bearer your-admin-secret-here', },});
const keys = await response.json();import requests
response = requests.get( 'https://api.horizonplatform.ai/admin/api-keys', headers={'Authorization': 'Bearer your-admin-secret-here'})
keys = response.json()Public Webhook Endpoints
Section titled “Public Webhook Endpoints”Webhook trigger endpoints do not require either an API key or admin secret. Instead, they authenticate via a token embedded in the URL path:
POST /api/webhooks/agent/{webhookToken}The token is validated by hashing it and comparing against the stored hash. Additional security is provided through optional IP allowlists and rate limiting configured on the webhook itself. See the Webhooks reference for details.
Key Rotation
Section titled “Key Rotation”To rotate an API key without downtime:
- Create a new API key with the same scopes using
POST /admin/api-keys. - Update your application to use the new key.
- Verify the new key is working correctly.
- Revoke the old key using
DELETE /admin/api-keys/:id.
For webhook tokens, use the dedicated rotation endpoint POST /api/agent-webhooks/:id/rotate, which generates a new token and invalidates the old one in a single operation.
Security Best Practices
Section titled “Security Best Practices”- Use the narrowest scopes possible. A key that only needs to read conversations should not have access to skill execution.
- Set expiration dates on keys used for temporary integrations or third-party access.
- Monitor rate limit headers to detect unusual usage patterns. See Rate Limiting.
- Rotate keys regularly, especially after team member departures or security incidents.
- Never log plaintext keys. The API returns the key only once at creation time; treat it like a password.
- Use environment variables to store keys and secrets in your application, never hardcode them in source files.