Authentication.
How Agent API keys work, security model, and authentication flow.
The Agent API uses long-lived API keys instead of login tokens. Each key is self-contained. It carries the identity, role, and permissions needed to authenticate a request.
How it works
Every request must include the key in the X-Agent-Key header:
curl -X GET https://your-domain.com/api/agent/v1/health \
-H "X-Agent-Key: rl_agent_a8f3k2m1x9v4b7n2..."
The authentication flow:
- Extract the key from the
X-Agent-Keyheader - Detect the key role from the prefix (
rl_admin_,rl_agent_,rl_member_) - Lookup candidate keys by prefix (indexed database query, fast)
- Verify the raw key against the stored bcrypt hash
- Check the key is active and not expired
- Check the key's owner account is active
- Bind the key and owner to the request for downstream use
Key format
A key contains its role prefix followed by 40 random characters:
rl_agent_ + 40 random characters
The stored lookup prefix contains the role prefix and the first eight random characters. Those eight characters are part of the 40, not an extra segment. The platform stores a bcrypt hash of the full key. The plaintext lookup prefix lets it find candidate records before checking the hash.
Key roles
Each key belongs to one owner type:
| Prefix | Role | Owner |
|---|---|---|
rl_admin_ |
Admin | Administrator account |
rl_agent_ |
Partner | Partner (business) account |
rl_member_ |
Member | Customer account |
All three key types are available.
Security model
One-time display
The dashboard shows the full key once, at creation. After you close the dialog, only the prefix remains visible. There is no way to retrieve the full key. If you lose it, create a new one.
Bcrypt hashing
The platform stores keys as bcrypt hashes, the same algorithm it uses for passwords. This means:
- Database leaks don't expose keys, and even administrators cannot see the full key
- Verification cost depends on the configured hash cost and server hardware
Rate limiting
Each key has a configurable rate limit (requests per minute, default: 60). The platform enforces the limit per key in a 1-minute fixed window. Two keys owned by the same partner have separate limits.
Authenticated requests that reach rate limiting include these headers. Authentication and feature-gate failures may omit them:
X-RateLimit-Limit: 60 ← max requests per window
X-RateLimit-Remaining: 42 ← requests left in current window
X-RateLimit-Reset: 1741260000 ← reported Unix reset timestamp
Successful responses report a reset timestamp about one minute ahead; do not treat it as the exact current window boundary. On HTTP 429, honor Retry-After:
{
"error": true,
"code": "RATE_LIMITED",
"message": "Too many requests. Please slow down.",
"retry_strategy": "backoff",
"details": {
"limit": 60,
"window_seconds": 60,
"retry_after_seconds": 23
}
}
Expiration
Keys can have an expiration date. Authentication rejects expired keys. Use this for temporary integrations or scheduled key rotation.
Owner activity check
Even a valid key fails when its owner account is inactive. When an admin disables a partner account, every key that partner owns stops working at once.
Authentication errors
All authentication errors follow the standard error envelope:
| Error Code | HTTP Status | Meaning |
|---|---|---|
AUTH_MISSING_KEY |
401 | No X-Agent-Key header provided |
AUTH_INVALID_KEY |
401 | Key format is wrong, prefix not found, or hash doesn't match |
AUTH_KEY_REVOKED |
401 | Key exists but is no longer active |
AUTH_KEY_EXPIRED |
401 | Key has passed its expiration date |
AUTH_OWNER_INACTIVE |
403 | The owner account is inactive |
AUTH_ANONYMOUS_MEMBER |
403 | Anonymous members cannot use Integration API keys |
Example error response:
{
"error": true,
"code": "AUTH_KEY_REVOKED",
"message": "This Integration API key has been revoked.",
"retry_strategy": "no_retry"
}
See Error Handling for the full error envelope format.
Best practices
| Practice | Why It Matters |
|---|---|
| Store keys in environment variables | Never hardcode keys in source code |
| Use the minimum required scopes | Least privilege: grant only what the integration needs |
| Set expiration dates | Limit blast radius of compromised keys |
| Rotate keys on a schedule | Create a new key, update your integration, revoke the old one |
| Monitor the audit log | Watch for unexpected patterns in Activity logs |
| Use HTTPS | The key travels in a request header. Unencrypted connections expose it |
Related topics
- Enabling & Managing Keys: Create and revoke keys in the dashboard
- Scopes & Permissions: What each key may do
- Error Handling: Standard error response format