Authentication
Authenticate every CrystalQore API request with an API key, tenant ID, and — when the operation is user-scoped — a user email.
Authentication
Every request to /api/v1 identifies who is calling (the API client), which organization to use, and optionally which user the call should act as.
Headers
| Header | Required | Example |
|---|---|---|
X-API-Key | Yes (or Bearer) | cq_ + 64 hex characters |
Authorization | Alternative to X-API-Key | Bearer cq_… |
X-Tenant-Id | Yes | Tenant UUID |
X-User-Email | Per operation | jordan@example.com |
Content-Type | On JSON bodies | application/json |
Send either X-API-Key or Authorization: Bearer cq_…, not a session cookie. Browser cookies from the CrystalQore app are not accepted.
API keys
Keys are created by CrystalQore operators (Superadmin → API Clients). The full key is shown once.
- Format:
cq_followed by 64 hexadecimal characters - Stored as a hash; only an 11-character prefix is kept for logs
- Disable, rotate, or delete a client from the same screen
- Each client has its own permissions, tenant allow-list, rate limit, and optional browser origins
Treat the key like a password. Do not commit it, put it in a mobile app, or share it across integrations. Use one client per system.
Tenant isolation
X-Tenant-Id must be a tenant the client is allowed to access (allow all tenants or an explicit tenant list). A valid key for tenant A cannot read tenant B.
If the tenant is disabled, or the client is not entitled to that tenant, the API returns TENANT_DISABLED or TENANT_ACCESS_DENIED.
User context
X-User-Email must match an enabled user in that tenant. The email is compared case-insensitively.
Required for:
POST /contacts,POST /click2dial- All chat conversation and message calls
GETandPOST /calendarPUT /presence
Optional for reads such as users, CDR, contacts, files, fax, and presence. When you send it on CDR or contacts, results are limited to that user.
Missing required user → MISSING_USER_EMAIL. Unknown or disabled user → USER_NOT_FOUND or USER_DISABLED.
Entitlement
After the key and tenant are valid, the API checks the platform.api capability on the tenant. Organizations without API access receive ENTITLEMENT_REQUIRED or SUBSCRIPTION_INACTIVE.
Browser CORS
Server-to-server calls do not need CORS. Browser calls only receive CORS headers when the client's allowed origins list includes that Origin (or *). The playground on docs.crystalqore.com uses a same-origin proxy so you do not need to add the docs site as an origin.
Failed auth
| Code | HTTP | Meaning |
|---|---|---|
MISSING_API_KEY | 401 | No key header |
INVALID_API_KEY_FORMAT | 401 | Key is not cq_ + 64 hex |
INVALID_API_KEY | 401 | Unknown or revoked key |
CLIENT_DISABLED | 403 | Client is disabled |
MISSING_TENANT_ID | 400 | No X-Tenant-Id |
TENANT_ACCESS_DENIED | 403 | Tenant not on the client |
TENANT_DISABLED | 403 | Tenant is disabled |
ENTITLEMENT_REQUIRED | 403 | Tenant cannot use the API |
MISSING_USER_EMAIL | 400 | User header required |
USER_NOT_FOUND | 404 | Email not in this tenant |
USER_DISABLED | 403 | User is disabled |