Skip to content

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.

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.1
Host: api.horizonplatform.ai
x-api-key: hz_live_abc123def456...

Each API key has the following properties:

PropertyDescription
client_nameA human-readable label identifying the key’s owner or purpose.
scopesAn array of strings defining which skill categories the key can access.
rate_limitMaximum requests per minute. Defaults to 100.
expires_atOptional expiration timestamp. The key is rejected after this time.
enabledWhether the key is currently active. Revoked keys have this set to false.

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 skills
  • sage-intacct — Access to Sage Intacct skills
  • web — Access to web skills
  • platform — Access to platform management skills
  • conversations — Access to conversation endpoints
  • memory — Access to agent memory endpoints
  • scheduler — Access to scheduled job endpoints
  • webhooks — Access to webhook management endpoints

A key can hold multiple scopes:

{
"client_name": "backend-service",
"scopes": ["quickbooks", "conversations", "memory"]
}
Terminal window
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()

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.1
Host: api.horizonplatform.ai
Authorization: Bearer your-admin-secret-here
Content-Type: application/json

Option 2: x-admin-secret header

POST /admin/api-keys HTTP/1.1
Host: api.horizonplatform.ai
x-admin-secret: your-admin-secret-here
Content-Type: application/json

Admin endpoints include:

  • POST /admin/api-keys — Create a new API key
  • GET /admin/api-keys — List all API keys
  • DELETE /admin/api-keys/:id — Revoke an API key
Terminal window
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()

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.

To rotate an API key without downtime:

  1. Create a new API key with the same scopes using POST /admin/api-keys.
  2. Update your application to use the new key.
  3. Verify the new key is working correctly.
  4. 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.

  • 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.