Diagnose and resolve API connection errors, authentication failures, and integration issues.
The Zenovay REST API is available on paid plans (Pro and above). Free-plan keys are rejected with a 403 API_PAID_PLAN_REQUIRED response — upgrade to use API keys.
Authentication Errors
"Invalid API Key" (401)
Common causes:
-
Wrong key format
- API key must start with
zv_prefix - Keys without this prefix are invalid
- Check you copied the full key from dashboard
- API key must start with
-
Key revoked
- Go to Settings → Account → Security & access and open the Personal API keys section
- Create a new key if the existing one was revoked
-
Key only saved once
- The full key is shown only at creation time — only the prefix is stored afterward
- If you didn't copy it, create a new key
Fix:
// Wrong - invalid format
const key = 'abc123_not_valid...';
// Correct - Zenovay API key
const key = 'zv_xyz789abc...';
"API Key Not Found" (401)
Check header format:
# Wrong
curl -H "Api-Key: zv_..."
# Correct (External API)
curl -H "X-API-Key: zv_..."
"API requires a paid plan" (403)
The REST API is a paid feature. A key created on (or now tied to) a Free-tier team returns:
{
"error": "The Zenovay API requires a paid plan. Upgrade to Pro or higher to use API keys.",
"code": "API_PAID_PLAN_REQUIRED"
}
Fix: Upgrade the team to Pro or higher, then create the key under Settings → Account → Security & access → Personal API keys.
"Access denied to this website" (403)
A personal API key is scoped two ways when you create it:
| Setting | Options |
|---|---|
| Permissions | Full access, or only Read / Write / Admin |
| Team access | All teams you belong to, or only selected teams |
A key can only reach websites in the teams it's allowed to act on (and only while you're still a member of those teams). If a request returns 403 for a specific website, the team that owns it is likely outside the key's team access, or you no longer belong to that team. Review the key under Settings → Account → Security & access → Personal API keys, or create a key with the access you need.
Connection Errors
"Connection Refused"
Check endpoint:
Correct: https://api.zenovay.com/api/external/v1/
Wrong: http://api.zenovay.com/api/external/v1/ (no HTTPS)
Wrong: https://zenovay.com/api/ (wrong domain)
"Connection Timeout"
Causes:
- Network issues
- Firewall blocking
- DNS resolution failure
Debug steps:
-
Test connectivity:
curl -v https://api.zenovay.com/api/external/v1/usage -
Check DNS:
nslookup api.zenovay.com -
Check firewall:
- Allow outbound HTTPS (443)
- Allow api.zenovay.com domain
"SSL Certificate Error"
Causes:
- Outdated root certificates
- Corporate proxy interference
- Clock skew on server
Fix:
# Update certificates (Ubuntu)
sudo apt update && sudo apt install ca-certificates
# Check system time
date
# If using Node.js, don't disable verification:
// DON'T DO THIS IN PRODUCTION
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
Rate Limit Errors
"Rate Limit Exceeded" (429)
Response headers:
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 2026-06-13T12:01:00.000Z
Retry-After: 42
The API also returns your monthly usage on every response:
X-Usage-Monthly: 4231
X-Usage-Limit: 10000
Implement backoff:
async function apiCallWithRetry(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error.status === 429) {
const retryAfter = error.headers.get('Retry-After') || 60;
await sleep(retryAfter * 1000);
continue;
}
throw error;
}
}
}
REST API rate limits
The REST API is rate-limited per key, by plan tier — both a per-minute rate and a monthly request quota:
| Plan | Per minute | Per month |
|---|---|---|
| Pro | 30 req/min | 10,000 |
| Scale | 60 req/min | 100,000 |
| Enterprise | 120 req/min | 1,000,000 |
Exceeding the per-minute rate returns 429 with Retry-After. Exceeding the monthly quota returns 429 and resets at the start of the next month (see the X-Usage-Monthly / X-Usage-Limit headers).
Tracking and public endpoint limits
The tracking ingest and other public endpoints are rate-limited per IP (not per plan), independent of REST API key limits:
| Context | Limit |
|---|---|
| Tracking (burst) | 60 req/10 sec per IP |
| Tracking (sustained) | 5,000 req/hour per IP |
| Public endpoints | 30 req/min per IP |
| Auth endpoints | 30 req/min per IP |
Request Errors
"Bad Request" (400)
Common issues:
-
Invalid JSON:
// Wrong - trailing comma { "name": "Test", } // Correct { "name": "Test" } -
Missing or malformed query parameters:
# Wrong - invalid date range GET /api/external/v1/analytics/{websiteId}?from=yesterday # Correct - ISO dates GET /api/external/v1/analytics/{websiteId}?from=2026-06-01&to=2026-06-13 -
Wrong data types in a request body:
// Wrong - string instead of number { "page": "1" } // Correct { "page": 1 }
"Not Found" (404)
Check:
- Endpoint URL is correct
- Resource ID exists
- Resource belongs to your account
# Verify endpoint (note the /api/external/v1 prefix and plural "websites")
GET /api/external/v1/websites/{websiteId} # Correct
GET /api/external/v1/website/{websiteId} # Wrong (singular)
"Unprocessable Entity" (422)
Validation failed. Check response body:
{
"error": "validation_error",
"details": {
"url": "Invalid URL format",
"name": "Name too long (max 100 characters)"
}
}
SDK Errors
JavaScript SDK
"Zenovay not defined":
<!-- Ensure script loaded -->
<script src="https://api.zenovay.com/z.js"
data-tracking-code="YOUR_TRACKING_CODE"></script>
<!-- Check after load -->
<script>
window.addEventListener('load', () => {
if (typeof zenovay !== 'undefined') {
console.log('Zenovay loaded');
}
});
</script>
Server-Side API Calls
Connection issues with the tracking endpoint:
// Use fetch with the tracking endpoint - no npm package needed.
// The ingest endpoint validates the payload, so send the full event:
// session_id (min 8 chars), an absolute url, user_agent, and the
// device fields (device_type, browser, os) are all required.
const response = await fetch('https://api.zenovay.com/e/YOUR_TRACKING_CODE', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
event_type: 'pageview',
url: 'https://example.com/home',
session_id: 'srv-session-abcdef',
user_agent: 'MyServer/1.0',
device_type: 'desktop',
browser: 'Server',
os: 'Linux',
}),
});
if (!response.ok) {
console.error('Zenovay tracking error:', response.status);
}
Timeout errors:
// Use AbortController for timeout control
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 30000);
const response = await fetch('https://api.zenovay.com/e/YOUR_TRACKING_CODE', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
event_type: 'pageview',
url: 'https://example.com/home',
session_id: 'srv-session-abcdef',
user_agent: 'MyServer/1.0',
device_type: 'desktop',
browser: 'Server',
os: 'Linux',
}),
signal: controller.signal,
});
clearTimeout(timeout);
Debugging Tips
Enable Debug Mode
In server-side calls:
// Enable verbose logging for External API calls
const response = await fetch('https://api.zenovay.com/api/external/v1/websites', {
headers: { 'X-API-Key': 'zv_...' },
});
console.log('Status:', response.status);
console.log('Response:', await response.json());
In tracking script:
<script data-tracking-code="YOUR_TRACKING_CODE"
data-debug="true"
src="..."></script>
Check API Status
- Visit status.zenovay.com
- Check API endpoint status
- Review incident history
Check key activity
In the dashboard:
- Go to Settings → Account → Security & access and find your Personal API keys
- Select a key to open its detail view
- Review its activity — accepted-event counts over the last 24 hours, 7 days, and all time, plus when the key was last used
Test with cURL
# Test API key with usage endpoint
curl -H "X-API-Key: zv_..." \
https://api.zenovay.com/api/external/v1/usage
# List websites
curl -H "X-API-Key: zv_..." \
https://api.zenovay.com/api/external/v1/websites
# With verbose output
curl -v -H "X-API-Key: zv_..." \
https://api.zenovay.com/api/external/v1/websites
Common Error Codes
| Code | Meaning | Solution |
|---|---|---|
| 400 | Bad request | Check request body |
| 401 | Unauthorized | Check API key |
| 403 | Forbidden | Check permissions |
| 404 | Not found | Check endpoint/ID |
| 422 | Validation failed | Check field values |
| 429 | Rate limited | Implement backoff |
| 500 | Server error | Retry, contact support |
| 502 | Bad gateway | Retry in 1 minute |
| 503 | Unavailable | Check status page |
Contacting Support
When reporting API issues, include:
-
Request details:
- Endpoint URL
- HTTP method
- Request headers (redact API key)
- Request body
-
Response details:
- Status code
- Response body
- Response headers
-
Context:
- Timestamp
- Request ID (from headers)
- SDK version if applicable
Email: [email protected]