- Remove all upstream project references from descriptions (Casdoor, Casvisor, Casibase, Infisical, LiteLLM, Langfuse, LibreChat, ActivePieces, Umami, Meilisearch, Qdrant, Harbor, Neon, Valkey, CoreDNS, OpenZiti, KubeRay, KubeFlow, Agnost) - Add email: [email protected] to all 27 contact blocks - Rewrite nexus/openapi.yaml from Swagger 2.0 to OpenAPI 3.1.0 (was still raw Casibase spec with [email protected]) - Fix IAM: [email protected] → [email protected], Casdoor → Hanzo IAM - Fix Cloud: "Swagger Docs" → proper Hanzo Cloud API description - Fix O11y: Loki/Prometheus refs → LogQL/PromQL - 28 files, 64,266 total lines, all valid YAML
2722 lines
71 KiB
YAML
2722 lines
71 KiB
YAML
openapi: 3.1.0
|
|
info:
|
|
title: Hanzo Analytics API
|
|
version: 1.0.0
|
|
description: Web analytics API for tracking website traffic, events, sessions, and generating reports.
|
|
contact:
|
|
name: Hanzo AI
|
|
url: https://hanzo.ai
|
|
email: [email protected]
|
|
license:
|
|
name: MIT
|
|
url: https://opensource.org/licenses/MIT
|
|
|
|
servers:
|
|
- url: https://analytics.hanzo.ai
|
|
description: Production
|
|
|
|
tags:
|
|
- name: Auth
|
|
description: Authentication and session management
|
|
- name: Websites
|
|
description: Website CRUD and data retrieval
|
|
- name: Events
|
|
description: Event collection and querying
|
|
- name: Sessions
|
|
description: Session tracking and analytics
|
|
- name: Pageviews
|
|
description: Pageview statistics
|
|
- name: Stats
|
|
description: Aggregate website statistics
|
|
- name: Reports
|
|
description: Report creation, management, and execution
|
|
- name: Teams
|
|
description: Team management and membership
|
|
- name: Users
|
|
description: User management
|
|
- name: Admin
|
|
description: Admin-only endpoints
|
|
- name: Me
|
|
description: Current user endpoints
|
|
- name: Share
|
|
description: Public share links
|
|
- name: Realtime
|
|
description: Realtime visitor data
|
|
- name: Collect
|
|
description: Data collection (tracker)
|
|
|
|
security:
|
|
- BearerAuth: []
|
|
|
|
components:
|
|
securitySchemes:
|
|
BearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
|
|
parameters:
|
|
websiteId:
|
|
name: websiteId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
sessionId:
|
|
name: sessionId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
userId:
|
|
name: userId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
teamId:
|
|
name: teamId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
reportId:
|
|
name: reportId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
shareId:
|
|
name: shareId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
startAt:
|
|
name: startAt
|
|
in: query
|
|
required: true
|
|
description: Start timestamp in milliseconds
|
|
schema:
|
|
type: integer
|
|
format: int64
|
|
endAt:
|
|
name: endAt
|
|
in: query
|
|
required: true
|
|
description: End timestamp in milliseconds
|
|
schema:
|
|
type: integer
|
|
format: int64
|
|
page:
|
|
name: page
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
pageSize:
|
|
name: pageSize
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
orderBy:
|
|
name: orderBy
|
|
in: query
|
|
schema:
|
|
type: string
|
|
search:
|
|
name: search
|
|
in: query
|
|
schema:
|
|
type: string
|
|
timezone:
|
|
name: timezone
|
|
in: query
|
|
schema:
|
|
type: string
|
|
example: America/Los_Angeles
|
|
unit:
|
|
name: unit
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [minute, hour, day, week, month, year]
|
|
|
|
schemas:
|
|
User:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
username:
|
|
type: string
|
|
role:
|
|
type: string
|
|
enum: [admin, user, view-only]
|
|
logoUrl:
|
|
type: string
|
|
nullable: true
|
|
displayName:
|
|
type: string
|
|
nullable: true
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
deletedAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
|
|
Website:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
domain:
|
|
type: string
|
|
nullable: true
|
|
shareId:
|
|
type: string
|
|
nullable: true
|
|
resetAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
userId:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
teamId:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
createdBy:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
deletedAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
|
|
Session:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
websiteId:
|
|
type: string
|
|
format: uuid
|
|
browser:
|
|
type: string
|
|
nullable: true
|
|
os:
|
|
type: string
|
|
nullable: true
|
|
device:
|
|
type: string
|
|
nullable: true
|
|
screen:
|
|
type: string
|
|
nullable: true
|
|
language:
|
|
type: string
|
|
nullable: true
|
|
country:
|
|
type: string
|
|
nullable: true
|
|
region:
|
|
type: string
|
|
nullable: true
|
|
city:
|
|
type: string
|
|
nullable: true
|
|
distinctId:
|
|
type: string
|
|
nullable: true
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
|
|
Team:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
accessCode:
|
|
type: string
|
|
nullable: true
|
|
logoUrl:
|
|
type: string
|
|
nullable: true
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
deletedAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
|
|
TeamUser:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
teamId:
|
|
type: string
|
|
format: uuid
|
|
userId:
|
|
type: string
|
|
format: uuid
|
|
role:
|
|
type: string
|
|
enum: [team-member, team-view-only, team-manager, team-owner]
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
user:
|
|
$ref: '#/components/schemas/User'
|
|
|
|
Report:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
userId:
|
|
type: string
|
|
format: uuid
|
|
websiteId:
|
|
type: string
|
|
format: uuid
|
|
type:
|
|
type: string
|
|
enum: [funnel, insights, retention, utm, goals, journey, revenue, attribution]
|
|
name:
|
|
type: string
|
|
description:
|
|
type: string
|
|
parameters:
|
|
type: object
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
|
|
Metric:
|
|
type: object
|
|
properties:
|
|
x:
|
|
type: string
|
|
y:
|
|
type: number
|
|
|
|
StatValue:
|
|
type: object
|
|
properties:
|
|
value:
|
|
type: number
|
|
prev:
|
|
type: number
|
|
|
|
PageviewSeries:
|
|
type: object
|
|
properties:
|
|
t:
|
|
type: string
|
|
y:
|
|
type: number
|
|
|
|
PaginatedResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items: {}
|
|
count:
|
|
type: integer
|
|
page:
|
|
type: integer
|
|
pageSize:
|
|
type: integer
|
|
|
|
DateRange:
|
|
type: object
|
|
required: [startDate, endDate]
|
|
properties:
|
|
startDate:
|
|
type: string
|
|
format: date-time
|
|
endDate:
|
|
type: string
|
|
format: date-time
|
|
num:
|
|
type: number
|
|
offset:
|
|
type: number
|
|
unit:
|
|
type: string
|
|
value:
|
|
type: string
|
|
|
|
ReportParams:
|
|
type: object
|
|
required: [websiteId, dateRange]
|
|
properties:
|
|
websiteId:
|
|
type: string
|
|
format: uuid
|
|
dateRange:
|
|
$ref: '#/components/schemas/DateRange'
|
|
|
|
FilterParams:
|
|
type: object
|
|
description: Optional filter parameters for narrowing query results
|
|
properties:
|
|
url:
|
|
type: string
|
|
referrer:
|
|
type: string
|
|
title:
|
|
type: string
|
|
query:
|
|
type: string
|
|
os:
|
|
type: string
|
|
browser:
|
|
type: string
|
|
device:
|
|
type: string
|
|
country:
|
|
type: string
|
|
region:
|
|
type: string
|
|
city:
|
|
type: string
|
|
tag:
|
|
type: string
|
|
host:
|
|
type: string
|
|
language:
|
|
type: string
|
|
event:
|
|
type: string
|
|
|
|
SendPayload:
|
|
type: object
|
|
required: [type, payload]
|
|
properties:
|
|
type:
|
|
type: string
|
|
enum: [event, identify]
|
|
payload:
|
|
type: object
|
|
required: [website]
|
|
properties:
|
|
website:
|
|
type: string
|
|
format: uuid
|
|
data:
|
|
type: object
|
|
hostname:
|
|
type: string
|
|
maxLength: 100
|
|
language:
|
|
type: string
|
|
maxLength: 35
|
|
referrer:
|
|
type: string
|
|
screen:
|
|
type: string
|
|
maxLength: 11
|
|
title:
|
|
type: string
|
|
url:
|
|
type: string
|
|
name:
|
|
type: string
|
|
maxLength: 50
|
|
tag:
|
|
type: string
|
|
maxLength: 50
|
|
ip:
|
|
type: string
|
|
format: ipv4
|
|
userAgent:
|
|
type: string
|
|
timestamp:
|
|
type: integer
|
|
description: Unix timestamp in seconds
|
|
id:
|
|
type: string
|
|
description: Distinct user identifier
|
|
|
|
Error:
|
|
type: object
|
|
properties:
|
|
error:
|
|
type: string
|
|
|
|
paths:
|
|
# ---------- Auth ----------
|
|
/api/auth/login:
|
|
post:
|
|
operationId: login
|
|
tags: [Auth]
|
|
summary: Log in with username and password
|
|
security: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [username, password]
|
|
properties:
|
|
username:
|
|
type: string
|
|
password:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Login successful
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
token:
|
|
type: string
|
|
user:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
username:
|
|
type: string
|
|
role:
|
|
type: string
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
isAdmin:
|
|
type: boolean
|
|
'401':
|
|
description: Incorrect username or password
|
|
|
|
/api/auth/logout:
|
|
post:
|
|
operationId: logout
|
|
tags: [Auth]
|
|
summary: Log out and invalidate token
|
|
responses:
|
|
'200':
|
|
description: Logged out
|
|
|
|
/api/auth/verify:
|
|
post:
|
|
operationId: verifyAuth
|
|
tags: [Auth]
|
|
summary: Verify current auth token
|
|
responses:
|
|
'200':
|
|
description: Token is valid
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/User'
|
|
'401':
|
|
description: Invalid token
|
|
|
|
/api/auth/sso:
|
|
post:
|
|
operationId: ssoAuth
|
|
tags: [Auth]
|
|
summary: Exchange SSO credentials for a session token
|
|
responses:
|
|
'200':
|
|
description: SSO token issued
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
user:
|
|
$ref: '#/components/schemas/User'
|
|
token:
|
|
type: string
|
|
|
|
# ---------- Collect ----------
|
|
/api/send:
|
|
post:
|
|
operationId: send
|
|
tags: [Collect]
|
|
summary: Send a single event or identify payload
|
|
security: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SendPayload'
|
|
responses:
|
|
'200':
|
|
description: Event accepted
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
cache:
|
|
type: string
|
|
description: Opaque cache token for subsequent requests
|
|
sessionId:
|
|
type: string
|
|
format: uuid
|
|
visitId:
|
|
type: string
|
|
format: uuid
|
|
|
|
/api/batch:
|
|
post:
|
|
operationId: batch
|
|
tags: [Collect]
|
|
summary: Send a batch of events
|
|
security: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/SendPayload'
|
|
responses:
|
|
'200':
|
|
description: Batch processed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
size:
|
|
type: integer
|
|
processed:
|
|
type: integer
|
|
errors:
|
|
type: integer
|
|
details:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
index:
|
|
type: integer
|
|
response:
|
|
type: object
|
|
|
|
/api/heartbeat:
|
|
get:
|
|
operationId: heartbeat
|
|
tags: [Auth]
|
|
summary: Health check
|
|
security: []
|
|
responses:
|
|
'200':
|
|
description: Service is running
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
ok:
|
|
type: boolean
|
|
|
|
# ---------- Me ----------
|
|
/api/me:
|
|
get:
|
|
operationId: getMe
|
|
tags: [Me]
|
|
summary: Get current authenticated user info
|
|
responses:
|
|
'200':
|
|
description: Current user auth context
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
user:
|
|
$ref: '#/components/schemas/User'
|
|
|
|
/api/me/password:
|
|
post:
|
|
operationId: changeMyPassword
|
|
tags: [Me]
|
|
summary: Change current user password
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [currentPassword, newPassword]
|
|
properties:
|
|
currentPassword:
|
|
type: string
|
|
newPassword:
|
|
type: string
|
|
minLength: 8
|
|
responses:
|
|
'200':
|
|
description: Password updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/User'
|
|
'400':
|
|
description: Current password is incorrect
|
|
|
|
/api/me/teams:
|
|
get:
|
|
operationId: getMyTeams
|
|
tags: [Me]
|
|
summary: List teams for the current user
|
|
parameters:
|
|
- $ref: '#/components/parameters/page'
|
|
- $ref: '#/components/parameters/pageSize'
|
|
- $ref: '#/components/parameters/orderBy'
|
|
- $ref: '#/components/parameters/search'
|
|
responses:
|
|
'200':
|
|
description: Paginated list of teams
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Team'
|
|
|
|
/api/me/websites:
|
|
get:
|
|
operationId: getMyWebsites
|
|
tags: [Me]
|
|
summary: List websites for the current user
|
|
parameters:
|
|
- $ref: '#/components/parameters/page'
|
|
- $ref: '#/components/parameters/pageSize'
|
|
- $ref: '#/components/parameters/orderBy'
|
|
- $ref: '#/components/parameters/search'
|
|
responses:
|
|
'200':
|
|
description: Paginated list of websites
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Website'
|
|
|
|
# ---------- Websites ----------
|
|
/api/websites:
|
|
get:
|
|
operationId: listWebsites
|
|
tags: [Websites]
|
|
summary: List websites owned by current user
|
|
parameters:
|
|
- $ref: '#/components/parameters/page'
|
|
- $ref: '#/components/parameters/pageSize'
|
|
- $ref: '#/components/parameters/orderBy'
|
|
- $ref: '#/components/parameters/search'
|
|
responses:
|
|
'200':
|
|
description: Paginated list of websites
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Website'
|
|
post:
|
|
operationId: createWebsite
|
|
tags: [Websites]
|
|
summary: Create a new website
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [name, domain]
|
|
properties:
|
|
name:
|
|
type: string
|
|
maxLength: 100
|
|
domain:
|
|
type: string
|
|
maxLength: 500
|
|
shareId:
|
|
type: string
|
|
maxLength: 50
|
|
nullable: true
|
|
teamId:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
responses:
|
|
'200':
|
|
description: Website created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Website'
|
|
|
|
/api/websites/{websiteId}:
|
|
get:
|
|
operationId: getWebsite
|
|
tags: [Websites]
|
|
summary: Get website by ID
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
responses:
|
|
'200':
|
|
description: Website details
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Website'
|
|
post:
|
|
operationId: updateWebsite
|
|
tags: [Websites]
|
|
summary: Update website
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [name, domain]
|
|
properties:
|
|
name:
|
|
type: string
|
|
domain:
|
|
type: string
|
|
shareId:
|
|
type: string
|
|
nullable: true
|
|
responses:
|
|
'200':
|
|
description: Website updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Website'
|
|
delete:
|
|
operationId: deleteWebsite
|
|
tags: [Websites]
|
|
summary: Delete website
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
responses:
|
|
'200':
|
|
description: Website deleted
|
|
|
|
/api/websites/{websiteId}/active:
|
|
get:
|
|
operationId: getActiveVisitors
|
|
tags: [Websites]
|
|
summary: Get count of active visitors
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
responses:
|
|
'200':
|
|
description: Active visitor count
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
x:
|
|
type: integer
|
|
description: Number of active visitors
|
|
|
|
/api/websites/{websiteId}/daterange:
|
|
get:
|
|
operationId: getWebsiteDateRange
|
|
tags: [Websites]
|
|
summary: Get the date range of data available for a website
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
responses:
|
|
'200':
|
|
description: Date range
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
minDate:
|
|
type: string
|
|
format: date-time
|
|
maxDate:
|
|
type: string
|
|
format: date-time
|
|
|
|
/api/websites/{websiteId}/reset:
|
|
post:
|
|
operationId: resetWebsite
|
|
tags: [Websites]
|
|
summary: Reset all data for a website
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
responses:
|
|
'200':
|
|
description: Website data reset
|
|
|
|
/api/websites/{websiteId}/transfer:
|
|
post:
|
|
operationId: transferWebsite
|
|
tags: [Websites]
|
|
summary: Transfer website ownership to another user or team
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
userId:
|
|
type: string
|
|
format: uuid
|
|
description: Transfer to this user (mutually exclusive with teamId)
|
|
teamId:
|
|
type: string
|
|
format: uuid
|
|
description: Transfer to this team (mutually exclusive with userId)
|
|
responses:
|
|
'200':
|
|
description: Website transferred
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Website'
|
|
|
|
/api/websites/{websiteId}/values:
|
|
get:
|
|
operationId: getWebsiteValues
|
|
tags: [Websites]
|
|
summary: Get distinct values for a given column type
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
- name: type
|
|
in: query
|
|
required: true
|
|
description: Column type (e.g. browser, os, device, country, url, referrer, title, event, tag, language, region, city, host)
|
|
schema:
|
|
type: string
|
|
- name: search
|
|
in: query
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Sorted list of distinct values
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: string
|
|
|
|
# ---------- Stats ----------
|
|
/api/websites/{websiteId}/stats:
|
|
get:
|
|
operationId: getWebsiteStats
|
|
tags: [Stats]
|
|
summary: Get aggregate statistics for a website
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
- name: compare
|
|
in: query
|
|
description: Compare period (e.g. "previous_period")
|
|
schema:
|
|
type: string
|
|
- name: url
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: referrer
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: title
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: os
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: browser
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: device
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: country
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: region
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: city
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: tag
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: host
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: language
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: event
|
|
in: query
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Stats with current and previous period values
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
pageviews:
|
|
$ref: '#/components/schemas/StatValue'
|
|
visitors:
|
|
$ref: '#/components/schemas/StatValue'
|
|
visits:
|
|
$ref: '#/components/schemas/StatValue'
|
|
bounces:
|
|
$ref: '#/components/schemas/StatValue'
|
|
totalTime:
|
|
$ref: '#/components/schemas/StatValue'
|
|
|
|
/api/websites/{websiteId}/metrics:
|
|
get:
|
|
operationId: getWebsiteMetrics
|
|
tags: [Stats]
|
|
summary: Get breakdown metrics by type (url, referrer, browser, os, device, country, event, channel, etc.)
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
- name: type
|
|
in: query
|
|
required: true
|
|
description: Metric type to break down by
|
|
schema:
|
|
type: string
|
|
enum: [url, referrer, title, browser, os, device, country, region, city, language, event, tag, host, query, channel]
|
|
- name: limit
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
- name: offset
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
- name: search
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: url
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: referrer
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: title
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: os
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: browser
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: device
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: country
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: region
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: city
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: tag
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: host
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: language
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: event
|
|
in: query
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Metric breakdown
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Metric'
|
|
|
|
# ---------- Pageviews ----------
|
|
/api/websites/{websiteId}/pageviews:
|
|
get:
|
|
operationId: getPageviews
|
|
tags: [Pageviews]
|
|
summary: Get pageview and session time series
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
- $ref: '#/components/parameters/unit'
|
|
- $ref: '#/components/parameters/timezone'
|
|
- name: compare
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: url
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: referrer
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: title
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: os
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: browser
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: device
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: country
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: region
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: city
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: tag
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: host
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: language
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: event
|
|
in: query
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Pageview and session series data
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
pageviews:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/PageviewSeries'
|
|
sessions:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/PageviewSeries'
|
|
startDate:
|
|
type: string
|
|
format: date-time
|
|
endDate:
|
|
type: string
|
|
format: date-time
|
|
compare:
|
|
type: object
|
|
properties:
|
|
pageviews:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/PageviewSeries'
|
|
sessions:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/PageviewSeries'
|
|
startDate:
|
|
type: string
|
|
format: date-time
|
|
endDate:
|
|
type: string
|
|
format: date-time
|
|
|
|
# ---------- Events ----------
|
|
/api/websites/{websiteId}/events:
|
|
get:
|
|
operationId: getEvents
|
|
tags: [Events]
|
|
summary: Get paginated list of events
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
- $ref: '#/components/parameters/page'
|
|
- $ref: '#/components/parameters/pageSize'
|
|
- $ref: '#/components/parameters/orderBy'
|
|
- $ref: '#/components/parameters/search'
|
|
responses:
|
|
'200':
|
|
description: Paginated event list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
/api/websites/{websiteId}/events/series:
|
|
get:
|
|
operationId: getEventSeries
|
|
tags: [Events]
|
|
summary: Get event metrics as a time series
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
- $ref: '#/components/parameters/unit'
|
|
- $ref: '#/components/parameters/timezone'
|
|
- name: url
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: referrer
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: title
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: os
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: browser
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: device
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: country
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: region
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: city
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: tag
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: host
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: language
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: event
|
|
in: query
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Event time series
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/PageviewSeries'
|
|
|
|
# ---------- Event Data ----------
|
|
/api/websites/{websiteId}/event-data/events:
|
|
get:
|
|
operationId: getEventDataEvents
|
|
tags: [Events]
|
|
summary: Get event data grouped by event name
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
- name: event
|
|
in: query
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Event data events
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
/api/websites/{websiteId}/event-data/fields:
|
|
get:
|
|
operationId: getEventDataFields
|
|
tags: [Events]
|
|
summary: Get event data fields
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
responses:
|
|
'200':
|
|
description: Event data fields
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
propertyName:
|
|
type: string
|
|
dataType:
|
|
type: integer
|
|
total:
|
|
type: integer
|
|
|
|
/api/websites/{websiteId}/event-data/properties:
|
|
get:
|
|
operationId: getEventDataProperties
|
|
tags: [Events]
|
|
summary: Get event data properties
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
- name: propertyName
|
|
in: query
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Event data properties
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
/api/websites/{websiteId}/event-data/values:
|
|
get:
|
|
operationId: getEventDataValues
|
|
tags: [Events]
|
|
summary: Get event data values for a property
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
- name: eventName
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: propertyName
|
|
in: query
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Event data values
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
/api/websites/{websiteId}/event-data/stats:
|
|
get:
|
|
operationId: getEventDataStats
|
|
tags: [Events]
|
|
summary: Get event data aggregate stats
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
- name: propertyName
|
|
in: query
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Event data stats
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
# ---------- Sessions ----------
|
|
/api/websites/{websiteId}/sessions:
|
|
get:
|
|
operationId: getSessions
|
|
tags: [Sessions]
|
|
summary: Get paginated list of sessions
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
- $ref: '#/components/parameters/page'
|
|
- $ref: '#/components/parameters/pageSize'
|
|
- $ref: '#/components/parameters/orderBy'
|
|
- $ref: '#/components/parameters/search'
|
|
responses:
|
|
'200':
|
|
description: Paginated session list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Session'
|
|
|
|
/api/websites/{websiteId}/sessions/stats:
|
|
get:
|
|
operationId: getSessionStats
|
|
tags: [Sessions]
|
|
summary: Get aggregate session statistics
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
- name: url
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: referrer
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: title
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: os
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: browser
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: device
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: country
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: region
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: city
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: tag
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: host
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: language
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: event
|
|
in: query
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Session stats
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
additionalProperties:
|
|
type: object
|
|
properties:
|
|
value:
|
|
type: number
|
|
|
|
/api/websites/{websiteId}/sessions/weekly:
|
|
get:
|
|
operationId: getSessionsWeekly
|
|
tags: [Sessions]
|
|
summary: Get weekly session breakdown
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
- $ref: '#/components/parameters/timezone'
|
|
- $ref: '#/components/parameters/page'
|
|
- $ref: '#/components/parameters/pageSize'
|
|
- $ref: '#/components/parameters/orderBy'
|
|
- $ref: '#/components/parameters/search'
|
|
responses:
|
|
'200':
|
|
description: Weekly session data
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
/api/websites/{websiteId}/sessions/{sessionId}:
|
|
get:
|
|
operationId: getSession
|
|
tags: [Sessions]
|
|
summary: Get a single session by ID
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/sessionId'
|
|
responses:
|
|
'200':
|
|
description: Session details
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Session'
|
|
|
|
/api/websites/{websiteId}/sessions/{sessionId}/activity:
|
|
get:
|
|
operationId: getSessionActivity
|
|
tags: [Sessions]
|
|
summary: Get activity log for a session
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/sessionId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
responses:
|
|
'200':
|
|
description: Session activity entries
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
eventName:
|
|
type: string
|
|
nullable: true
|
|
urlPath:
|
|
type: string
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
|
|
/api/websites/{websiteId}/sessions/{sessionId}/properties:
|
|
get:
|
|
operationId: getSessionProperties
|
|
tags: [Sessions]
|
|
summary: Get custom session data properties
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/sessionId'
|
|
responses:
|
|
'200':
|
|
description: Session data key-value pairs
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
# ---------- Session Data ----------
|
|
/api/websites/{websiteId}/session-data/properties:
|
|
get:
|
|
operationId: getSessionDataProperties
|
|
tags: [Sessions]
|
|
summary: Get distinct session data property names
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
- name: propertyName
|
|
in: query
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Session data properties
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
/api/websites/{websiteId}/session-data/values:
|
|
get:
|
|
operationId: getSessionDataValues
|
|
tags: [Sessions]
|
|
summary: Get session data values for a property
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
- name: propertyName
|
|
in: query
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Session data values
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
# ---------- Reports (CRUD) ----------
|
|
/api/reports:
|
|
get:
|
|
operationId: listReports
|
|
tags: [Reports]
|
|
summary: List reports, optionally filtered by website or team
|
|
parameters:
|
|
- name: websiteId
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- name: teamId
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- $ref: '#/components/parameters/page'
|
|
- $ref: '#/components/parameters/pageSize'
|
|
- $ref: '#/components/parameters/orderBy'
|
|
- $ref: '#/components/parameters/search'
|
|
responses:
|
|
'200':
|
|
description: Paginated list of reports
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Report'
|
|
post:
|
|
operationId: createReport
|
|
tags: [Reports]
|
|
summary: Create a new report
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [websiteId, name, type, description, parameters]
|
|
properties:
|
|
websiteId:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
maxLength: 200
|
|
type:
|
|
type: string
|
|
enum: [funnel, insights, retention, utm, goals, journey, revenue, attribution]
|
|
description:
|
|
type: string
|
|
maxLength: 500
|
|
parameters:
|
|
type: object
|
|
responses:
|
|
'200':
|
|
description: Report created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Report'
|
|
|
|
/api/reports/{reportId}:
|
|
get:
|
|
operationId: getReport
|
|
tags: [Reports]
|
|
summary: Get a report by ID
|
|
parameters:
|
|
- $ref: '#/components/parameters/reportId'
|
|
responses:
|
|
'200':
|
|
description: Report details
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Report'
|
|
'404':
|
|
description: Report not found
|
|
post:
|
|
operationId: updateReport
|
|
tags: [Reports]
|
|
summary: Update a report
|
|
parameters:
|
|
- $ref: '#/components/parameters/reportId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [websiteId, type, name, description, parameters]
|
|
properties:
|
|
websiteId:
|
|
type: string
|
|
format: uuid
|
|
type:
|
|
type: string
|
|
enum: [funnel, insights, retention, utm, goals, journey, revenue, attribution]
|
|
name:
|
|
type: string
|
|
maxLength: 200
|
|
description:
|
|
type: string
|
|
maxLength: 500
|
|
parameters:
|
|
type: object
|
|
responses:
|
|
'200':
|
|
description: Report updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Report'
|
|
delete:
|
|
operationId: deleteReport
|
|
tags: [Reports]
|
|
summary: Delete a report
|
|
parameters:
|
|
- $ref: '#/components/parameters/reportId'
|
|
responses:
|
|
'200':
|
|
description: Report deleted
|
|
|
|
/api/websites/{websiteId}/reports:
|
|
get:
|
|
operationId: getWebsiteReports
|
|
tags: [Reports]
|
|
summary: List reports for a specific website
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/page'
|
|
- $ref: '#/components/parameters/pageSize'
|
|
- $ref: '#/components/parameters/orderBy'
|
|
- $ref: '#/components/parameters/search'
|
|
responses:
|
|
'200':
|
|
description: Paginated report list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Report'
|
|
|
|
# ---------- Report Execution ----------
|
|
/api/reports/funnel:
|
|
post:
|
|
operationId: runFunnelReport
|
|
tags: [Reports]
|
|
summary: Run a funnel report
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [websiteId, dateRange, window, steps]
|
|
properties:
|
|
websiteId:
|
|
type: string
|
|
format: uuid
|
|
dateRange:
|
|
$ref: '#/components/schemas/DateRange'
|
|
window:
|
|
type: number
|
|
description: Funnel window in minutes
|
|
minimum: 1
|
|
steps:
|
|
type: array
|
|
minItems: 2
|
|
items:
|
|
type: object
|
|
required: [type, value]
|
|
properties:
|
|
type:
|
|
type: string
|
|
value:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Funnel results
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
/api/reports/insights:
|
|
post:
|
|
operationId: runInsightsReport
|
|
tags: [Reports]
|
|
summary: Run an insights report
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [websiteId, dateRange, fields, filters]
|
|
properties:
|
|
websiteId:
|
|
type: string
|
|
format: uuid
|
|
dateRange:
|
|
$ref: '#/components/schemas/DateRange'
|
|
fields:
|
|
type: array
|
|
minItems: 1
|
|
items:
|
|
type: object
|
|
required: [name, type, label]
|
|
properties:
|
|
name:
|
|
type: string
|
|
type:
|
|
type: string
|
|
label:
|
|
type: string
|
|
filters:
|
|
type: array
|
|
items:
|
|
type: object
|
|
required: [name, type, operator, value]
|
|
properties:
|
|
name:
|
|
type: string
|
|
type:
|
|
type: string
|
|
operator:
|
|
type: string
|
|
value:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Insights results
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
/api/reports/retention:
|
|
post:
|
|
operationId: runRetentionReport
|
|
tags: [Reports]
|
|
summary: Run a retention report
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [websiteId, dateRange, timezone]
|
|
properties:
|
|
websiteId:
|
|
type: string
|
|
format: uuid
|
|
dateRange:
|
|
$ref: '#/components/schemas/DateRange'
|
|
timezone:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Retention cohort data
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
/api/reports/goals:
|
|
post:
|
|
operationId: runGoalsReport
|
|
tags: [Reports]
|
|
summary: Run a goals report
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [websiteId, dateRange, goals]
|
|
properties:
|
|
websiteId:
|
|
type: string
|
|
format: uuid
|
|
dateRange:
|
|
$ref: '#/components/schemas/DateRange'
|
|
goals:
|
|
type: array
|
|
minItems: 1
|
|
items:
|
|
type: object
|
|
required: [type, value, goal]
|
|
properties:
|
|
type:
|
|
type: string
|
|
enum: [url, event, event-data]
|
|
value:
|
|
type: string
|
|
goal:
|
|
type: number
|
|
operator:
|
|
type: string
|
|
enum: [count, sum, average]
|
|
description: Required when type is event-data
|
|
property:
|
|
type: string
|
|
description: Required when type is event-data
|
|
responses:
|
|
'200':
|
|
description: Goals results
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
/api/reports/journey:
|
|
post:
|
|
operationId: runJourneyReport
|
|
tags: [Reports]
|
|
summary: Run a user journey report
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [websiteId, dateRange, steps]
|
|
properties:
|
|
websiteId:
|
|
type: string
|
|
format: uuid
|
|
dateRange:
|
|
$ref: '#/components/schemas/DateRange'
|
|
steps:
|
|
type: integer
|
|
minimum: 3
|
|
maximum: 7
|
|
startStep:
|
|
type: string
|
|
endStep:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Journey flow data
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
/api/reports/utm:
|
|
post:
|
|
operationId: runUtmReport
|
|
tags: [Reports]
|
|
summary: Run a UTM report
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [websiteId, dateRange]
|
|
properties:
|
|
websiteId:
|
|
type: string
|
|
format: uuid
|
|
dateRange:
|
|
$ref: '#/components/schemas/DateRange'
|
|
responses:
|
|
'200':
|
|
description: UTM breakdown data
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
/api/reports/revenue:
|
|
get:
|
|
operationId: getRevenueValues
|
|
tags: [Reports]
|
|
summary: Get available revenue values for a website
|
|
parameters:
|
|
- name: websiteId
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- name: startDate
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
- name: endDate
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
responses:
|
|
'200':
|
|
description: Revenue values
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
post:
|
|
operationId: runRevenueReport
|
|
tags: [Reports]
|
|
summary: Run a revenue report
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [websiteId, dateRange, currency, timezone]
|
|
properties:
|
|
websiteId:
|
|
type: string
|
|
format: uuid
|
|
dateRange:
|
|
$ref: '#/components/schemas/DateRange'
|
|
currency:
|
|
type: string
|
|
timezone:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Revenue time series
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
/api/reports/attribution:
|
|
post:
|
|
operationId: runAttributionReport
|
|
tags: [Reports]
|
|
summary: Run an attribution report
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [websiteId, dateRange, model, steps]
|
|
properties:
|
|
websiteId:
|
|
type: string
|
|
format: uuid
|
|
dateRange:
|
|
$ref: '#/components/schemas/DateRange'
|
|
model:
|
|
type: string
|
|
enum: [firstClick, lastClick]
|
|
steps:
|
|
type: array
|
|
minItems: 1
|
|
items:
|
|
type: object
|
|
required: [type, value]
|
|
properties:
|
|
type:
|
|
type: string
|
|
value:
|
|
type: string
|
|
currency:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Attribution data
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
|
|
# ---------- Users ----------
|
|
/api/users:
|
|
post:
|
|
operationId: createUser
|
|
tags: [Users]
|
|
summary: Create a new user (admin only)
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [username, password, role]
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
username:
|
|
type: string
|
|
maxLength: 255
|
|
password:
|
|
type: string
|
|
role:
|
|
type: string
|
|
enum: [admin, user, view-only]
|
|
responses:
|
|
'200':
|
|
description: User created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/User'
|
|
'400':
|
|
description: User already exists
|
|
|
|
/api/users/{userId}:
|
|
get:
|
|
operationId: getUser
|
|
tags: [Users]
|
|
summary: Get user by ID
|
|
parameters:
|
|
- $ref: '#/components/parameters/userId'
|
|
responses:
|
|
'200':
|
|
description: User details
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/User'
|
|
post:
|
|
operationId: updateUser
|
|
tags: [Users]
|
|
summary: Update user
|
|
parameters:
|
|
- $ref: '#/components/parameters/userId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [username]
|
|
properties:
|
|
username:
|
|
type: string
|
|
maxLength: 255
|
|
password:
|
|
type: string
|
|
maxLength: 255
|
|
role:
|
|
type: string
|
|
enum: [admin, user, view-only]
|
|
responses:
|
|
'200':
|
|
description: User updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/User'
|
|
delete:
|
|
operationId: deleteUser
|
|
tags: [Users]
|
|
summary: Delete user (admin only)
|
|
parameters:
|
|
- $ref: '#/components/parameters/userId'
|
|
responses:
|
|
'200':
|
|
description: User deleted
|
|
'400':
|
|
description: Cannot delete yourself
|
|
|
|
/api/users/{userId}/teams:
|
|
get:
|
|
operationId: getUserTeams
|
|
tags: [Users]
|
|
summary: List teams a user belongs to
|
|
parameters:
|
|
- $ref: '#/components/parameters/userId'
|
|
- $ref: '#/components/parameters/page'
|
|
- $ref: '#/components/parameters/pageSize'
|
|
- $ref: '#/components/parameters/orderBy'
|
|
- $ref: '#/components/parameters/search'
|
|
responses:
|
|
'200':
|
|
description: Paginated team list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Team'
|
|
|
|
/api/users/{userId}/websites:
|
|
get:
|
|
operationId: getUserWebsites
|
|
tags: [Users]
|
|
summary: List websites owned by a user
|
|
parameters:
|
|
- $ref: '#/components/parameters/userId'
|
|
- $ref: '#/components/parameters/page'
|
|
- $ref: '#/components/parameters/pageSize'
|
|
- $ref: '#/components/parameters/orderBy'
|
|
- $ref: '#/components/parameters/search'
|
|
responses:
|
|
'200':
|
|
description: Paginated website list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Website'
|
|
|
|
/api/users/{userId}/usage:
|
|
get:
|
|
operationId: getUserUsage
|
|
tags: [Users]
|
|
summary: Get event usage breakdown for a user (admin only)
|
|
parameters:
|
|
- $ref: '#/components/parameters/userId'
|
|
- $ref: '#/components/parameters/startAt'
|
|
- $ref: '#/components/parameters/endAt'
|
|
responses:
|
|
'200':
|
|
description: Usage data
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
websiteEventUsage:
|
|
type: integer
|
|
eventDataUsage:
|
|
type: integer
|
|
websites:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
websiteId:
|
|
type: string
|
|
format: uuid
|
|
websiteName:
|
|
type: string
|
|
websiteEventUsage:
|
|
type: integer
|
|
eventDataUsage:
|
|
type: integer
|
|
|
|
# ---------- Teams ----------
|
|
/api/teams:
|
|
post:
|
|
operationId: createTeam
|
|
tags: [Teams]
|
|
summary: Create a new team
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [name]
|
|
properties:
|
|
name:
|
|
type: string
|
|
maxLength: 50
|
|
responses:
|
|
'200':
|
|
description: Team created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Team'
|
|
|
|
/api/teams/join:
|
|
post:
|
|
operationId: joinTeam
|
|
tags: [Teams]
|
|
summary: Join a team using an access code
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [accessCode]
|
|
properties:
|
|
accessCode:
|
|
type: string
|
|
maxLength: 50
|
|
responses:
|
|
'200':
|
|
description: Joined team
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TeamUser'
|
|
'400':
|
|
description: Already a team member
|
|
'404':
|
|
description: Team not found
|
|
|
|
/api/teams/{teamId}:
|
|
get:
|
|
operationId: getTeam
|
|
tags: [Teams]
|
|
summary: Get team by ID (includes members)
|
|
parameters:
|
|
- $ref: '#/components/parameters/teamId'
|
|
responses:
|
|
'200':
|
|
description: Team details with members
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Team'
|
|
'404':
|
|
description: Team not found
|
|
post:
|
|
operationId: updateTeam
|
|
tags: [Teams]
|
|
summary: Update team (owner only)
|
|
parameters:
|
|
- $ref: '#/components/parameters/teamId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
name:
|
|
type: string
|
|
maxLength: 50
|
|
accessCode:
|
|
type: string
|
|
maxLength: 50
|
|
responses:
|
|
'200':
|
|
description: Team updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Team'
|
|
delete:
|
|
operationId: deleteTeam
|
|
tags: [Teams]
|
|
summary: Delete team (owner only)
|
|
parameters:
|
|
- $ref: '#/components/parameters/teamId'
|
|
responses:
|
|
'200':
|
|
description: Team deleted
|
|
|
|
/api/teams/{teamId}/users:
|
|
get:
|
|
operationId: getTeamUsers
|
|
tags: [Teams]
|
|
summary: List team members
|
|
parameters:
|
|
- $ref: '#/components/parameters/teamId'
|
|
- $ref: '#/components/parameters/page'
|
|
- $ref: '#/components/parameters/pageSize'
|
|
- $ref: '#/components/parameters/orderBy'
|
|
- $ref: '#/components/parameters/search'
|
|
responses:
|
|
'200':
|
|
description: Paginated team member list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/TeamUser'
|
|
post:
|
|
operationId: addTeamUser
|
|
tags: [Teams]
|
|
summary: Add a user to a team
|
|
parameters:
|
|
- $ref: '#/components/parameters/teamId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [userId, role]
|
|
properties:
|
|
userId:
|
|
type: string
|
|
format: uuid
|
|
role:
|
|
type: string
|
|
enum: [team-member, team-view-only, team-manager]
|
|
responses:
|
|
'200':
|
|
description: User added to team
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TeamUser'
|
|
'400':
|
|
description: User is already a member
|
|
|
|
/api/teams/{teamId}/users/{userId}:
|
|
get:
|
|
operationId: getTeamUser
|
|
tags: [Teams]
|
|
summary: Get a team member
|
|
parameters:
|
|
- $ref: '#/components/parameters/teamId'
|
|
- $ref: '#/components/parameters/userId'
|
|
responses:
|
|
'200':
|
|
description: Team user details
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TeamUser'
|
|
post:
|
|
operationId: updateTeamUser
|
|
tags: [Teams]
|
|
summary: Update team member role (owner only)
|
|
parameters:
|
|
- $ref: '#/components/parameters/teamId'
|
|
- $ref: '#/components/parameters/userId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [role]
|
|
properties:
|
|
role:
|
|
type: string
|
|
enum: [team-member, team-view-only, team-manager]
|
|
responses:
|
|
'200':
|
|
description: Team user updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TeamUser'
|
|
delete:
|
|
operationId: removeTeamUser
|
|
tags: [Teams]
|
|
summary: Remove user from team
|
|
parameters:
|
|
- $ref: '#/components/parameters/teamId'
|
|
- $ref: '#/components/parameters/userId'
|
|
responses:
|
|
'200':
|
|
description: User removed from team
|
|
|
|
/api/teams/{teamId}/websites:
|
|
get:
|
|
operationId: getTeamWebsites
|
|
tags: [Teams]
|
|
summary: List websites belonging to a team
|
|
parameters:
|
|
- $ref: '#/components/parameters/teamId'
|
|
- $ref: '#/components/parameters/page'
|
|
- $ref: '#/components/parameters/pageSize'
|
|
- $ref: '#/components/parameters/orderBy'
|
|
- $ref: '#/components/parameters/search'
|
|
responses:
|
|
'200':
|
|
description: Paginated website list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Website'
|
|
|
|
# ---------- Admin ----------
|
|
/api/admin/users:
|
|
get:
|
|
operationId: adminListUsers
|
|
tags: [Admin]
|
|
summary: List all users (admin only)
|
|
parameters:
|
|
- $ref: '#/components/parameters/page'
|
|
- $ref: '#/components/parameters/pageSize'
|
|
- $ref: '#/components/parameters/orderBy'
|
|
- $ref: '#/components/parameters/search'
|
|
responses:
|
|
'200':
|
|
description: Paginated user list with website counts
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
allOf:
|
|
- $ref: '#/components/schemas/User'
|
|
- type: object
|
|
properties:
|
|
_count:
|
|
type: object
|
|
properties:
|
|
websiteUser:
|
|
type: integer
|
|
|
|
/api/admin/websites:
|
|
get:
|
|
operationId: adminListWebsites
|
|
tags: [Admin]
|
|
summary: List all websites for a user (admin only)
|
|
parameters:
|
|
- name: userId
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- name: includeOwnedTeams
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- name: includeAllTeams
|
|
in: query
|
|
schema:
|
|
type: string
|
|
- $ref: '#/components/parameters/page'
|
|
- $ref: '#/components/parameters/pageSize'
|
|
- $ref: '#/components/parameters/orderBy'
|
|
- $ref: '#/components/parameters/search'
|
|
responses:
|
|
'200':
|
|
description: Paginated website list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Website'
|
|
|
|
# ---------- Realtime ----------
|
|
/api/realtime/{websiteId}:
|
|
get:
|
|
operationId: getRealtimeData
|
|
tags: [Realtime]
|
|
summary: Get realtime visitor data for the last 30 minutes
|
|
parameters:
|
|
- $ref: '#/components/parameters/websiteId'
|
|
- $ref: '#/components/parameters/timezone'
|
|
responses:
|
|
'200':
|
|
description: Realtime data
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
|
|
# ---------- Share ----------
|
|
/api/share/{shareId}:
|
|
get:
|
|
operationId: getSharedWebsite
|
|
tags: [Share]
|
|
summary: Get a shared website by share ID (no auth required)
|
|
security: []
|
|
parameters:
|
|
- $ref: '#/components/parameters/shareId'
|
|
responses:
|
|
'200':
|
|
description: Shared website token
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
websiteId:
|
|
type: string
|
|
format: uuid
|
|
token:
|
|
type: string
|
|
'404':
|
|
description: Share not found
|
|
|
|
# ---------- Telemetry ----------
|
|
/api/scripts/telemetry:
|
|
get:
|
|
operationId: getTelemetryScript
|
|
tags: [Auth]
|
|
summary: Get telemetry pixel script
|
|
security: []
|
|
responses:
|
|
'200':
|
|
description: JavaScript telemetry snippet
|
|
content:
|
|
text/javascript:
|
|
schema:
|
|
type: string
|