REST API

Read your RevKlik analytics from your own code: scoped API tokens, JSON endpoints for sites, traffic, revenue and exports, and per-plan rate limits.

The REST API serves the same data as the dashboard, MCP server and CLI. All of them run on one shared query layer, so numbers match everywhere.

https://app.revklik.com/api/v1

Authenticate

Send an API token as a Bearer token on every request:

curl https://app.revklik.com/api/v1/whoami \
  -H "Authorization: Bearer rvt_YOUR_TOKEN"

Create tokens under Share → API tokens (see share and access). The full token is shown once; RevKlik stores only a SHA-256 hash, so store it somewhere safe.

PrefixTypeAccess
rvt_AccountEvery site you own or were invited to, within the scopes granted
rv_SiteOne site. Only the analytics:read and analytics:export scopes

Only rvt_ and rv_ tokens

Dashboard session tokens are rejected by the public API with 401. Create an API token instead.

Scopes

ScopeAllows
sites:readList sites and read one site
analytics:readAll analytics endpoints except export
analytics:exportGET /analytics/export
events:writePOST /events/server (see server events API)
tokens:readList API tokens
tokens:writeCreate and revoke API tokens

Account tokens default to sites:read, analytics:read, analytics:export, tokens:read and tokens:write. Site tokens default to analytics:read and analytics:export. A site token used against another site gets 403.

Rate limits

Limits are per minute and depend on your plan:

PlanRequests per minuteAPI tokens
Micro302
Starter1205
Growth300Unlimited

Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (a Unix timestamp in seconds). When you go over, the API answers 429 with a Retry-After header in seconds.

Data older than your plan’s raw-event retention (30, 60 or 180 days for Micro, Starter and Growth) is no longer available to queries.

Response format

Successful responses wrap the payload in data:

{ "data": {}, "success": true }

Errors use the same envelope:

{ "error": "Insufficient scope: analytics:export required", "success": false }
StatusMeaning
400Invalid or missing parameter
401Token missing, malformed, unknown, expired, or its prefix does not match
403Missing scope, token bound to a different site, or token limit reached
404Site or token not found
429Rate limit exceeded

Account

GET /whoami

Describes the token in use. It needs no scope.

{
	"data": {
		"user": { "id": "abc123", "name": "Dewi", "email": "dewi@example.com" },
		"plan": "starter",
		"token": {
			"type": "account",
			"scopes": ["sites:read", "analytics:read"],
			"site_id": null,
			"name": "Reporting",
			"created_at": "2026-05-15T00:00:00Z"
		}
	},
	"success": true
}

GET /sites and GET /sites/:siteId

Requires sites:read. Account tokens list every site you own or were invited to; site tokens list only their own.

{
	"data": [
		{
			"id": "9f1c...",
			"name": "My Website",
			"domain": "mysite.com",
			"created_at": "2026-01-15T00:00:00Z"
		}
	],
	"success": true
}

Analytics

Every analytics endpoint requires analytics:read and these query parameters:

ParameterDescription
site_idSite ID. Required.
range24h, 7d, 30d or 90d; default 7d. Also an explicit start,end pair of ISO dates. Any other value falls back to 7d.
limitList endpoints only. Capped at 100.

Revenue is in major units of the site’s revenue currency; the response includes currency.

EndpointReturnsDefault limit
GET /analytics/overviewPageviews, visitors, sessions, bounce rate, average duration, revenue, conversionsn/a
GET /analytics/timeseriesPageviews and visitors per day (hourly for short ranges)n/a
GET /analytics/pagesTop pages10
GET /analytics/referrersTraffic sources with visitor share10
GET /analytics/geoCountry, region and city50
GET /analytics/devicesDevice, OS and browser breakdownsn/a
GET /analytics/revenueRevenue by source, by country and over timen/a
GET /analytics/campaignsUTM campaign performancen/a
GET /analytics/journeysRecent visitor journeys; optional path filter50
curl "https://app.revklik.com/api/v1/analytics/overview?site_id=SITE_ID&range=7d" \
  -H "Authorization: Bearer rvt_YOUR_TOKEN"
{
	"data": {
		"pageviews": 12483,
		"visitors": 3241,
		"sessions": 4812,
		"bounceRate": 34,
		"avgDuration": 252,
		"revenue": 2490000,
		"currency": "IDR",
		"conversions": 87
	},
	"success": true
}

bounceRate is a whole percentage and avgDuration is in seconds.

/analytics/pages returns path, pageviews and visitors per row. /analytics/devices returns devices, os and browsers arrays of { device, visitors, percentage }.

Export

GET /analytics/export requires analytics:export.

ParameterDescription
site_idRequired.
rangeSame values as above; default 30d.
formatcsv (default) or json.
typeevents (default), visitors or sessions.
event_typeOptional filter for events, such as pageview or conversion.
limitRows to return, 1 to 10000; default 10000.
curl "https://app.revklik.com/api/v1/analytics/export?site_id=SITE_ID&range=30d&format=csv&type=events" \
  -H "Authorization: Bearer rvt_YOUR_TOKEN" -o events.csv

Portfolio revenue

GET /portfolio/revenue?from=YYYY-MM-DD&to=YYYY-MM-DD&currency=IDR (scope analytics:read) totals revenue across every site you can access, converted into one currency. It is the same data the MCP portfolio_revenue tool returns.

Server events

POST /events/server (scope events:write) lets your backend report purchases, renewals and refunds. The request body and idempotency rules are in the server events API.

Manage tokens

These endpoints need an account token with the matching scope.

EndpointScopeDoes
GET /tokenstokens:readList your tokens (prefix only)
POST /tokenstokens:writeCreate a token
DELETE /tokens/:idtokens:writeRevoke a token; it stops working at once
curl -X POST https://app.revklik.com/api/v1/tokens \
  -H "Authorization: Bearer rvt_YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Reporting", "type": "account", "scopes": ["sites:read", "analytics:read"]}'

type is account or site. A site token also needs site_id, and only accepts the analytics scopes. The response contains the full token once, with id, prefix, scopes and created_at.

Examples

const res = await fetch(
	"https://app.revklik.com/api/v1/analytics/overview?site_id=SITE_ID&range=7d",
	{ headers: { Authorization: `Bearer ${process.env.REVKLIK_TOKEN}` } },
);
const { data } = await res.json();
console.log(data.visitors, data.revenue);
import os, requests

res = requests.get(
    "https://app.revklik.com/api/v1/analytics/overview",
    params={"site_id": "SITE_ID", "range": "7d"},
    headers={"Authorization": f"Bearer {os.environ['REVKLIK_TOKEN']}"},
)
print(res.json()["data"])
  • MCP server: the same data for Codex, Cursor and Claude
  • CLI: the same endpoints from your terminal