Authentication
Two kinds of key
Use a signed-in dashboard session, an API key, or a secret key. A key combines a public key_id with a private secret. Send both as one bearer value, never in the query string:
Authorization: Bearer ctr_<key_id>.<secret>
An API key (ctr_...) can only read. A secret key (ctr_mgmt_...) can also manage sites, measurement keys, goals, share links, reports, exports, and other keys. Account settings and uptime monitoring always require a browser session. Issue keys from Site tools.
Keys can cover one site or the whole account. A site-scoped key cannot create sites or manage API keys because those actions are account-wide.
Response contract
One envelope, always
Every response, success or failure, is JSON shaped the same way. Check ok; the HTTP status is authoritative.
{"ok": true, "data": {}}
{"ok": false, "error": {"code": "bad_range", "message": "end must be later than start"}}
The OpenAPI contract defines the contents of data for each operation. Listed resources use an id field; route parameters name the resource, such as {key_id}. Timestamps use ISO-8601 with a +00:00 offset, except /realtime, /visitors, /visitor-map, /session/{id}, which return RFC 1123 HTTP dates.
Ranges and pagination
Reading analytics
Analytics reads accept a preset range (today, yesterday, 7d, 30d, 90d, 6mo, 12mo) or paired ISO-8601 start/end values. Ranges are half-open: start <= timestamp < end.
Visitor and visitor-map feeds use opaque cursors. Return next_cursor unchanged and stop when has_more is false. Do not decode or construct cursors.
Examples
Copy, paste, adjust
curl -H 'Authorization: Bearer ctr_REDACTED.REDACTED' \
'https://webcounter.ca/api/v1/sites'
curl -H 'Authorization: Bearer ctr_REDACTED.REDACTED' \
'https://webcounter.ca/api/v1/s/example/overview?range=30d'
curl -X POST -H 'Authorization: Bearer ctr_mgmt_REDACTED.REDACTED' \
-H 'Content-Type: application/json' \
-d '{"slug":"example","name":"Example","timezone":"UTC"}' \
'https://webcounter.ca/api/v1/sites'
Use a separate site slug and test domain for experiments. Never send a production key, customer identifier, or raw visitor data to a third-party tool.
Data exports
Download raw CSV data
Use a secret key to queue an events or sessions export with POST /s/{slug}/exports. Poll GET .../exports/{export_id}, then fetch .../download when the state is done. Exports expire automatically.
What stays session-only
Not available to any key
Bearer keys cannot access account credentials, uptime-monitor settings or history, or Web Push enrollment. Those features require a signed-in browser session.
For AI agents
Machine-readable entry points
Start with /llms.txt, then read /static/openapi.yaml for paths, parameters, schemas, and authentication requirements.