API Endpoints
Zenovay provides several API endpoint groups for accessing your analytics data programmatically.
Authentication
All API requests require authentication. The method depends on which API you use:
| API | Auth Method | Header | Use Case |
|---|---|---|---|
| External API | API Key | X-API-Key: YOUR_API_KEY | Server-side integrations, embedding analytics |
| Dashboard APIs (Conversations, Settings, Onboarding, Teams, Users) | Bearer JWT | Authorization: Bearer <token> | Dashboard and internal service operations |
| Widgets | None (public) | N/A | Embeddable widgets using tracking code |
| Real-Time Data | None (public) | N/A | Live visitor counts using tracking code |
Keep your API key secure! Never expose it in client-side code or commit it to version control. Get your API key from Settings > API Keys in the dashboard.
See Authentication for details on API key management.
External API
Base URL: https://api.zenovay.com/api/external/v1
Server-side API for accessing analytics data with API key authentication (X-API-Key header).
Available Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /usage | API usage statistics |
| GET | /websites | List all websites |
| GET | /websites/:id | Get website details |
| GET | /analytics/:websiteId | Full analytics summary |
| GET | /analytics/:websiteId/visitors | Visitor data |
| GET | /analytics/:websiteId/pages | Page statistics |
| GET | /analytics/:websiteId/countries | Geographic data |
| GET | /analytics/:websiteId/technology | Technology breakdown |
| GET | /heatmaps/:websiteId/pages | Heatmap page data |
| GET | /replays/:websiteId/sessions | Session replay data |
| GET | /errors/:websiteId/groups | Error tracking groups |
Each endpoint has a dedicated reference page with parameters, response schemas, TypeScript interfaces, and code examples in cURL, JavaScript, Python, and TypeScript.
See also the External API overview for a high-level introduction.
Embeddable Widgets
Base URL: https://api.zenovay.com/widgets
Ready-to-use widgets that require no authentication. Use your tracking code to identify the website.
| Method | Path | Description |
|---|---|---|
| GET | /:trackingCode/realtime | Live visitor count widget |
| GET | /:trackingCode/preview | 24-hour timeline widget |
| GET | /:trackingCode/recent | Country breakdown widget |
See Widgets for embedding examples.
Real-Time Data
Base URL: https://api.zenovay.com/e
Public JSON endpoints for live statistics. No authentication required.
| Method | Path | Description |
|---|---|---|
| GET | /live/:trackingCode | Current live visitor count |
| GET | /realtime/:websiteId | Real-time analytics data |
| GET | /stats/:trackingCode | Visitor statistics summary |
| GET | /:trackingCode/status | Tracking status check |
See Real-Time Data for integration guides.
Rate Limits
API rate limits vary by plan:
| Plan | Requests per Minute | Monthly Limit |
|---|---|---|
| Free | 10 | 1,000 |
| Pro | 30 | 10,000 |
| Scale | 60 | 100,000 |
| Enterprise | 120 | 1,000,000 |
Rate limit headers are included in all responses:
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 29
X-RateLimit-Reset: 1642771200
The X-RateLimit-Limit value reflects your plan's per-minute limit (e.g., 10 for Free, 30 for Pro, 60 for Scale, 120 for Enterprise).
See Rate Limits for details on handling rate limit errors.
Error Codes
| Status Code | Description |
|---|---|
| 200 | Success |
| 400 | Bad Request |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Not Found |
| 429 | Too Many Requests |
| 500 | Internal Server Error |
{
"success": true,
"data": { ... },
"timestamp": "2026-02-07T12:00:00.000Z"
}{
"success": false,
"error": {
"message": "The provided API key is missing or invalid",
"code": "UNAUTHORIZED",
"timestamp": "2026-02-07T12:00:00.000Z"
}
}Webhooks
Set up webhooks to receive real-time notifications:
Available Events
visitor.identified- When a visitor is identifiedvisitor.high_value- When visitor score reaches 80+event.tracked- When any event is trackedgoal.completed- When a goal is completedvisitor.converted- When a visitor converts
Webhook Payload
{
"event": "visitor.high_value",
"timestamp": "2025-01-20T15:30:00Z",
"data": {
"visitor_id": "vis_abc123",
"score": 92,
"current_page": "/pricing",
"time_on_site": 420
}
}Dashboard API Overview
The following API groups power the Zenovay dashboard. All endpoints require a Bearer JWT token in the Authorization header. Responses use a standard envelope:
{ "success": true, "data": { ... }, "timestamp": "..." }
Role-Based Permissions
Website Settings endpoints enforce role-based access. Roles in order of privilege:
| Role | Level | Can do |
|---|---|---|
| owner | 4 | Full access including billing and deletion |
| admin | 3 | Manage settings, integrations, team members |
| editor | 2 | Edit content and basic settings |
| viewer | 1 | Read-only access |
Conversations API
Base URL: https://api.zenovay.com/api/conversations
Auth: Bearer JWT required. Team membership verified for all requests.
CRUD operations for AI-powered conversations within teams. The team_id query parameter defaults to the authenticated user's organization if not provided.
Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /conversations?team_id=:teamId | List conversations for a team |
| GET | /conversations/:id | Get conversation with messages |
| POST | /conversations | Create a new conversation |
| PUT | /conversations/:id | Update a conversation |
| DELETE | /conversations/:id | Delete a conversation |
| POST | /conversations/:id/messages | Append a message |
GET /conversations
Returns conversations without message content for performance.
Query Parameters:
team_id(optional) — defaults to user's organization
{
"success": true,
"data": [
{
"id": "uuid",
"team_id": "uuid",
"title": "Analytics Q3 review",
"created_at": "2026-02-01T10:00:00Z",
"updated_at": "2026-02-07T14:30:00Z"
}
]
}GET /conversations/:id
Returns the full conversation including the messages array.
{
"success": true,
"data": {
"id": "uuid",
"team_id": "uuid",
"title": "Analytics Q3 review",
"messages": [
{ "role": "user", "content": "Show top pages", "timestamp": "2026-02-07T14:30:00Z" },
{ "role": "assistant", "content": "Here are your top pages...", "timestamp": "2026-02-07T14:30:01Z" }
],
"created_at": "2026-02-01T10:00:00Z",
"updated_at": "2026-02-07T14:30:01Z"
}
}POST /conversations
{
"title": "New conversation",
"team_id": "uuid"
}title(required) — non-empty stringteam_id(optional) — defaults to user's organization
Response: 201 with the created conversation (includes empty messages: []).
PUT /conversations/:id
{
"title": "Updated title",
"messages": [...]
}Both fields are optional. Accepts partial updates.
DELETE /conversations/:id
Response: 200 with { "deleted": true }.
POST /conversations/:id/messages
Appends a message to the conversation. The server adds a timestamp to each message.
{
"role": "user",
"content": "What were last week's top referrers?"
}role(required) — message role (e.g.,"user","assistant")content(required) — message text
Response: 201 with the full updated conversation including all messages.
Website Settings API
Base URL: https://api.zenovay.com/api/websites
Auth: Bearer JWT required. Each endpoint enforces a minimum role.
Manage website configuration including general settings, notifications, traffic exclusions, revenue tracking, domains, and team members. All paths are scoped by :websiteId.
Endpoints
| Method | Path | Min Role | Description |
|---|---|---|---|
| PUT | /:websiteId/general | editor | Update general settings |
| GET | /:websiteId/notifications | viewer | Get notification preferences |
| PUT | /:websiteId/notifications | editor | Update notification preferences |
| GET | /:websiteId/exclusions | viewer | Get IP and path exclusions |
| POST | /:websiteId/exclusions/ip | editor | Add an IP exclusion |
| DELETE | /:websiteId/exclusions/ip/:exclusionId | editor | Remove an IP exclusion |
| POST | /:websiteId/exclusions/path | editor | Add a path exclusion |
| DELETE | /:websiteId/exclusions/path/:exclusionId | editor | Remove a path exclusion |
| PUT | /:websiteId/revenue | admin | Update revenue settings |
| GET | /:websiteId/domains | viewer | Get domain configuration |
| PUT | /:websiteId/domains | admin | Update domain settings |
| GET | /:websiteId/team-members | viewer | List team members |
| POST | /:websiteId/team-members | admin | Invite a team member |
| PUT | /:websiteId/team-members/:memberId | admin | Update member role |
| DELETE | /:websiteId/team-members/:memberId | admin | Remove a team member |
PUT /:websiteId/general
{
"domain": "example.com",
"name": "My Website",
"timezone": "America/New_York",
"primary_color": "#4F46E5",
"kpi_goal": 10000,
"public_dashboard": true,
"allowed_domains": ["example.com", "www.example.com"]
}{
"success": true,
"data": {
"id": "uuid",
"domain": "example.com",
"name": "My Website",
"timezone": "America/New_York",
"primary_color": "#4F46E5",
"kpi_goal": 10000,
"public_dashboard": true,
"allowed_domains": ["example.com", "www.example.com"],
"updated_at": "2026-02-07T12:00:00Z"
}
}GET /:websiteId/notifications
Returns notification preferences. If none have been set, returns a default object with only the website_id.
PUT /:websiteId/notifications
Accepts any notification preference fields. Uses an upsert pattern: creates the record on first call, updates on subsequent calls.
GET /:websiteId/exclusions
Returns both IP and path exclusions in a single response.
{
"success": true,
"data": {
"ip_exclusions": [
{ "id": "uuid", "website_id": "uuid", "ip_address": "192.168.1.1", "description": "Office IP", "created_at": "..." }
],
"path_exclusions": [
{ "id": "uuid", "website_id": "uuid", "path_pattern": "/admin/*", "description": "Admin pages", "created_at": "..." }
]
}
}POST /:websiteId/exclusions/ip
{
"ip_address": "192.168.1.1",
"description": "Office IP"
}ip_address(required)description(optional)
Response: 201. Returns 409 if the IP is already excluded.
POST /:websiteId/exclusions/path
{
"path_pattern": "/admin/*",
"description": "Admin pages"
}path_pattern(required)description(optional)
Response: 201. Returns 409 if the path pattern is already excluded.
PUT /:websiteId/revenue
Requires admin role.
{
"revenue_provider": "stripe",
"revenue_currency": "USD"
}{
"success": true,
"data": {
"id": "uuid",
"revenue_provider": "stripe",
"revenue_currency": "USD",
"updated_at": "2026-02-07T12:00:00Z"
}
}GET /:websiteId/domains
{
"success": true,
"data": {
"primary_domain": "example.com",
"allowed_domains": ["example.com", "www.example.com"],
"verification_status": "verified"
}
}PUT /:websiteId/domains
Requires admin role.
{
"domain": "example.com",
"allowed_domains": ["example.com", "www.example.com"]
}allowed_domains must be an array if provided.
GET /:websiteId/team-members
Returns team members enriched with user profile data.
{
"success": true,
"data": [
{
"id": "membership_uuid",
"user_id": "user_uuid",
"role": "admin",
"created_at": "2026-01-15T10:00:00Z",
"deactivated_at": null,
"user": {
"id": "user_uuid",
"email": "[email protected]",
"full_name": "Jane Doe",
"avatar_url": "https://..."
}
}
]
}POST /:websiteId/team-members
Invite a user by email. Requires admin role.
{
"email": "[email protected]",
"role": "editor"
}email(required) — must be a registered Zenovay userrole(optional) — defaults to"viewer". Must be one of:owner,admin,editor,viewer
Response: 201. Returns 404 if the email is not found, 409 if already a member.
PUT /:websiteId/team-members/:memberId
Update a member's role. Requires admin role.
{
"role": "admin"
}role(required) — must be one of:owner,admin,editor,viewer
DELETE /:websiteId/team-members/:memberId
Removes a team member (soft-delete). Requires admin role.
Response: 200 with { "deleted": true }.
Onboarding API
Base URL: https://api.zenovay.com/api/onboarding
Auth: Bearer JWT required. User-scoped (no team or role checks).
Track user onboarding progress. Each user has a single onboarding record that persists across sessions.
Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /onboarding/progress | Get onboarding progress |
| POST | /onboarding/progress | Save onboarding progress |
GET /onboarding/progress
Returns the user's onboarding state. If no record exists, returns defaults.
{
"success": true,
"data": {
"user_id": "uuid",
"current_step": "add_website",
"completed": false,
"data": { "welcomed": true },
"created_at": "2026-02-01T10:00:00Z",
"updated_at": "2026-02-07T14:00:00Z"
}
}POST /onboarding/progress
Uses an upsert pattern: creates the record on first call, updates on subsequent calls.
{
"step": "install_tracking",
"data": { "welcomed": true, "website_added": true },
"completed": false
}step— saved ascurrent_stepin the databasedata— arbitrary JSON object for storing step-specific statecompleted— defaults tofalse
Teams API
Base URL: https://api.zenovay.com/api/teams
Auth: Bearer JWT required. Team membership verified (any active member can access).
Read-only team context endpoints for permissions, usage statistics, and member lists. For team management actions (invite, role changes, removal), use the Website Settings API team-members endpoints.
Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /teams/:id/permissions | Get permissions and plan context |
| GET | /teams/:id/usage | Get usage statistics for current billing period |
| GET | /teams/:id/members | List team members with profiles |
GET /teams/:id/permissions
Returns the authenticated user's role, the team's plan, current usage counts, and computed permission flags.
{
"success": true,
"data": {
"team_id": "uuid",
"role": "admin",
"plan": "Pro",
"plan_limits": {
"maxWebsites": 5,
"maxTeamMembers": 5,
"eventsPerMonth": 10000,
"dataRetentionDays": 730
},
"current_usage": {
"websites": 3,
"team_members": 5
},
"permissions": {
"can_manage_billing": false,
"can_manage_team": true,
"can_edit_settings": true,
"can_view": true
}
}
}GET /teams/:id/usage
Returns usage statistics for the current billing period (month to date).
{
"success": true,
"data": {
"team_id": "uuid",
"plan": "Pro",
"period": {
"start": "2026-02-01T00:00:00.000Z",
"end": "2026-02-07T12:00:00.000Z"
},
"usage": {
"events": 4521,
"events_limit": 10000,
"websites": 3,
"websites_limit": 10,
"team_members": 5,
"team_members_limit": 10
}
}
}GET /teams/:id/members
Returns team members enriched with user profile data.
{
"success": true,
"data": [
{
"id": "membership_uuid",
"user_id": "user_uuid",
"role": "admin",
"created_at": "2026-01-15T10:00:00Z",
"user": {
"id": "user_uuid",
"email": "[email protected]",
"full_name": "Jane Doe",
"name": "Jane",
"avatar_url": "https://..."
}
}
]
}User Profile API
Base URL: https://api.zenovay.com/api/users
Auth: Bearer JWT required. User-scoped (own profile only).
Manage the authenticated user's profile and email address.
Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /users/me | Get current user profile |
| PUT | /users/me | Update profile (name, email) |
| PUT | /users/me/email | Update email with SSO check |
| DELETE | /users/me | Delete user account |
| GET | /users/me/usage | Get usage statistics |
| GET | /users/me/plan-limits | Get plan limits and features |
PUT /users/me/email
Dedicated endpoint for email changes with SSO provider detection. If the user signed up via an OAuth provider (Google, GitHub, etc.), the request is rejected with a message to update the email through that provider instead.
{
"email": "[email protected]"
}email(required) — must be a valid email, different from the current one
Response: 200 with the updated user record. Returns 400 if the user is an SSO account or the email is invalid/unchanged.
Next Steps
Start integrating with the Zenovay API using the guides below.
- External API - Server-side analytics with API key auth
- Widgets - Pre-built embeddable widgets
- Real-Time Data - Live visitor data endpoints
- Authentication - API key management
- Rate Limits - Understanding limits