Authentication
Every authenticated request sends two headers: the project API key in
X-Zyneo-Key and the secret as a Bearer token.
GET /v1/projects/me HTTP/1.1
Host: accounts.zyneo.app
X-Zyneo-Key: zyneo_key_test_a1b2c3d4e5f6
Authorization: Bearer zyneo_sk_test_z9y8x7w6v5u4 Headers
| Header | Value | Required |
|---|---|---|
X-Zyneo-Key | Project API key (zyneo_key_test_… or zyneo_key_live_…) | Yes, on every authenticated endpoint |
Authorization | Bearer <secret> where the secret is zyneo_sk_test_… or zyneo_sk_live_… | Yes, on every authenticated endpoint |
The secret never belongs in a browser. Browser flows use
Zyneo hosted pages; only server-side code holds zyneo_sk_….
Error responses
All authentication failures return 401 with a JSON body:
{
"error": {
"code": "invalid_secret",
"message": "API key and secret do not match."
}
} | Code | Cause | Fix |
|---|---|---|
missing_credentials | One or both headers are absent. | Send both X-Zyneo-Key and Authorization. |
invalid_api_key | The key is malformed or does not belong to a known project. | Check the key starts with zyneo_key_test_ or zyneo_key_live_ and was issued to your project. |
invalid_secret | The secret is malformed or does not match this key. | Confirm you copied the full secret shown once at creation, with the Bearer prefix. |
Security properties
- Secrets are compared using constant-time equality against a stored SHA-256 hash — response timing does not reveal how much of your secret matched.
- Plaintext secrets are never stored. Only a hash plus a display prefix exist server-side.
- Test keys may call from localhost. Live keys require an allowlisted origin or server IP (enforced when live traffic opens).
Next step
Learn how credentials are structured in API keys.