API reference
API overview
On this page
The REST API sends events and payments from your server, reads every dashboard report, and manages chart notes, funnels, segments, settings, alerts and team members. Everything the dashboard, the CLI and the MCP server show comes from these endpoints.
Base URL
Every path on these pages is relative to https://metricraven.com/api/v1. Send JSON request bodies with Content-Type: application/json; every response is JSON, except 204 No Content.
curl 'https://metricraven.com/api/v1/stats/traffic?range=all' \
--header "Authorization: Bearer $METRICRAVEN_SECRET_KEY"Which key to use
Send a key as Authorization: Bearer …. How to create each one is in Authentication and access tokens.
| Credential | Use it for |
|---|---|
| Site secret key (ana_sec_…) | Your backend, for one website. The only key that sends events, identify calls, payments and crawler requests, and the only key besides the dashboard that deletes a person's data. Also reads every report and changes settings of its own website. |
| Account access token (mr_…) | Scripts, the CLI and AI assistants. Acts as you across websites, limited to its scopes, its websites and your role. Required for /account, /websites, /members and notification preferences. Never sends events or payments. |
| Share link token (?share=…) | Public and embedded dashboards. Read-only aggregate reports without names, emails or visitor IDs. Send it as the share query parameter instead of an Authorization header. |
The site parameter
- Account tokens must send exactly one
site=WEBSITE_IDon every website endpoint. A missing, repeated or unknownsite, or a website the token is limited away from, returns 401. - Site secret keys already identify their website, so
siteis optional. If you send it, it must be that key's website ID; any other value returns 401. - Website IDs look like
ana_pub_1a2b3c4d5e6f7a8b. List yours with GET /websites.
Access levels
Each website endpoint needs one of four access levels. A credential that lacks it gets 401.
| Level | Secret key | Account token | Share link |
|---|---|---|---|
| read: aggregate reports, funnels | Yes | read scope | Yes |
| live: realtime, chart notes, commits | Yes | read scope | No |
| private: people and private configuration | Yes | visitors scope | No |
| write: changes | Yes | write scope, admin or owner role | No |
Reports read with a share link, or with a token without the visitors scope, return null instead of customer names, emails, user IDs and visitor IDs. An account token on a website where you are a viewer can read but never write, whatever its scopes.
Endpoints
Send data (secret key only)
| Request | Reference |
|---|---|
| POST /events | Server-side goals |
| POST /identify | Identify users |
| POST /payments | Payments API |
| POST /crawls | Crawler requests (below) |
| POST /collect | The browser script and SDKs; no key, checked against your domains and app IDs. See Proxy. |
Reports
| Request | Access | Reference |
|---|---|---|
| GET /stats/traffic | read | Traffic |
| GET /stats/breakdown | read | Breakdown |
| GET /stats/filter-values | read | Filter values |
| GET /stats/conversions | read | Conversions and funnels |
| GET /stats/goal | read | One goal |
| GET /stats/insights | read | Buyer insights |
| GET /stats/revenue | read | Revenue |
| GET /stats/subscriptions | read | Subscriptions |
| GET /stats/search | read | Search Console |
| GET /stats/ads | read | Ad spend and ROAS, every network |
| GET /stats/meta-ads | read | Meta Ads only (alias) |
| GET /stats/currencies | read | Reporting currency and exchange rates |
| GET /stats/crawlers | read | Crawlers |
| GET /stats/crawler-pages | read | Crawled pages search |
| GET /stats/x-referrers | read | X links |
| GET /stats/mentions | read | Social mentions |
| GET /stats/ai-visibility | read | AI visibility |
| GET /stats/overview | read | Compact overview |
| GET /stats/live | live | Realtime |
| GET /stats/live/replay | live | Realtime replay |
| GET /stats/live/value | live | Value of visitors online |
| GET /stats/visitors | private | Visitor search |
| GET /stats/journeys | private | Journeys |
Website configuration and people
| Request | Access | Reference |
|---|---|---|
| GET /notes | live | Chart notes |
| POST /notes, PUT /notes/ID, DELETE /notes/ID | write | Chart notes |
| GET /commits | live | GitHub commits |
| GET /funnels | read | Funnels |
| POST /funnels, PUT /funnels/ID, DELETE /funnels/ID | write | Funnels |
| GET /segments | private | Segments |
| POST /segments, PUT /segments/ID, DELETE /segments/ID | write | Segments |
| GET /site | private | Settings |
| PUT /site | write | Settings |
| GET, POST /site/keys; PATCH, DELETE /site/keys/ID; POST /site/keys/ID/roll | write, no secret key | Secret keys |
| GET /goals/customizations | read, no share links | Goal names and colours |
| PUT, DELETE /goals/customizations | write | Goal names and colours |
| GET /visitors/VISITOR_ID | private | Visitor profile |
| DELETE /people | write, no tokens | Erase a person |
| DELETE /payments | write | Delete payments |
| DELETE /events | write | Delete goal events |
| GET, PUT, PATCH /bot-traffic/settings; GET, POST, PUT, DELETE /bot-traffic/token; GET /bot-traffic/usage | read / write, account token | Bot traffic settings |
| GET, POST, DELETE /managed-proxy; POST /managed-proxy/check; GET /managed-proxy/dns-provider | read / write, account token | Managed proxy |
| GET, POST /alerts; GET, PUT, DELETE /alerts/ID; GET /alerts/history | read / write, no share links | Conversion alerts |
| GET, PUT /notifications | token or dashboard only | Email preferences |
Account (account tokens only)
| Request | Reference |
|---|---|
| GET, PATCH /account | Account API |
| GET, POST /websites | Websites |
| GET, PATCH, DELETE /websites/ID | Update or delete a website |
| GET, POST /tokens; DELETE /tokens/ID | Access tokens |
| GET, POST /members; PATCH, DELETE /members/USER_ID; POST, DELETE /members/invites/ID | Team members |
| GET /health | Service status: ok, db and redis. No key. |
Responses
Most endpoints return the object itself: a report, or a list under a named key such as { "notes": [...] } or { "funnels": [...] }. Alerts, notification preferences and team members wrap their result as { "status": "success", "data": ... }. Social mentions return data, pagination and meta.
- Timestamps are ISO 8601 strings in UTC. Chart notes use calendar dates (YYYY-MM-DD).
- Money is in major units of the report currency: 29 means $29.00. Rates and percentages are 0–100, rounded to two decimals.
- A change between periods is a relative percentage, or
nullwhen the previous value is zero. - New fields can be added at any time; ignore those you don't know.
Errors
Errors have an HTTP status and a JSON body with a machine-readable error code. Many add a readable message; schema failures add details with the invalid fields.
{
"error": "invalid_payload",
"details": {
"formErrors": [],
"fieldErrors": { "currency": ["Invalid"] }
}
}| Status | Common error codes |
|---|---|
| 400 | invalid_json, invalid_payload, invalid_range, invalid_breakdown_query, invalid_filter_query, invalid_visitor_query, invalid_goal, invalid_steps, invalid_hours, invalid_currency, invalid_note, invalid_funnel, invalid_segment, invalid_settings, invalid_domain, invalid_request. |
| 401 unauthorized | Missing, mistyped, deleted or rotated key; missing or wrong site; a token without the scope; a website the token can't use; or a write your role doesn't allow. |
| 402 | tracking_paused: the plan's monthly event allowance is used up, so new events and payments are refused until the cycle resets or you upgrade. website_limit and member_limit: plan limits on the account API. |
| 403 | domain_not_allowed (crawler or browser event for a domain the website doesn't list), app_not_allowed, insufficient_scope or forbidden (account API), account_token_required (team endpoints called with a secret key), forbidden (account token on DELETE /people). |
| 404 | not_found (note, funnel, segment, visitor or person), unknown_funnel, unknown_site (collect). |
| 409 | note_limit, segment_limit, duplicate_segment_name, segment_changed (a stale segment revision: reload and retry). |
| 429 | rate_limited or too_many_attempts; see rate limits below. |
Rate limits
| Endpoint | Limit |
|---|---|
| POST /collect | 120 requests a minute per visitor IP and website. Over it: 429 rate_limited with Retry-After: 60. |
| POST /members (invitations) | 30 an hour per IP: 429 too_many_attempts. |
| MCP (/api/mcp) | 240 requests a minute per token or site key. |
| Report, configuration and server ingestion endpoints | No fixed request limit. Keep to a few concurrent requests per website. |
Reports are cached for 60 seconds per website, range and parameter set, so polling faster than once a minute returns the same numbers. Add fresh=1 to recompute.
Pagination and list sizes
Paginated endpoints take offset (rows to skip, default 0) and limit (1–100, default 50) and return total, offset and nextOffset. nextOffset is null on the last page.
curl --get 'https://metricraven.com/api/v1/stats/breakdown' \
--header "Authorization: Bearer $METRICRAVEN_SECRET_KEY" \
--data-urlencode 'range=all' \
--data-urlencode 'dimension=page' \
--data-urlencode 'limit=100' \
--data-urlencode 'offset=100'| Endpoint | Paging |
|---|---|
| /stats/breakdown, /stats/filter-values, /stats/visitors | offset, limit (1–100), total, nextOffset. |
| /stats/journeys | offset, limit (1–100, default 25) and total. |
| /stats/mentions | offset, limit (1–1000, default 100) and pagination.hasMore. |
| Lists inside reports | Top 50 per breakdown in /stats/traffic (countries are complete), top 50 crawler pages, 200 X links, 500 commits, 500 realtime visitors and 1,000 notes. Use /stats/breakdown for complete tables. |
Date ranges and time zones
| Parameter | Meaning |
|---|---|
| from, to | UTC instants in ISO 8601 with a Z suffix, for example 2026-10-01T00:00:00.000Z. Offsets such as +02:00 and plain dates are rejected. from is inclusive and to exclusive; from must be before to, at most 36,600 days apart. |
| range=all | Instead of from and to: from the start of the day of the website's first recorded event, payment or crawl, to now. |
| timezone | IANA zone such as Europe/Madrid (default UTC). Groups days, weeks and months, and the weekday/hour heatmaps, in that zone. It doesn't move from and to: send the UTC instants of your local midnight. |
| granularity | auto, hour, day (default), week or month. Hourly becomes daily over 3 days, daily becomes weekly over 400 days and weekly becomes monthly over 4,000 days. The value used is returned in period.granularity. |
Reports that compare periods use the window of the same length that ends at from. Chart notes, the subscriptions report and realtime endpoints take no range.
Send crawler requests
POST /crawls records one request by a crawler that your server or edge middleware handled. Crawlers rarely run JavaScript, so this is how AI and search bots reach /stats/crawlers. Ready-made middleware is in Bots and AI crawlers.
curl --request POST 'https://metricraven.com/api/v1/crawls' \
--header "Authorization: Bearer $METRICRAVEN_SECRET_KEY" \
--header 'Content-Type: application/json' \
--data '{
"url": "https://example.com/pricing",
"userAgent": "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
"status": 200
}'| Field | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | Full URL that was requested, up to 2,000 characters. Its host must be one of the website's domains. |
| userAgent | string | Yes | The request's User-Agent header, 1–1,000 characters. |
| status | integer | No | HTTP status you answered with, 100–599. |
| Response | Meaning |
|---|---|
| 200 { "ok": true, "bot": "GPTBot", "type": "ai-training" } | Recorded. |
| 200 { "ok": true, "ignored": "not_a_crawler" } | Not a known crawler, for example a normal browser. Nothing is stored; you can send every request. |
| 400 invalid_payload | Missing or invalid url, userAgent or status. |
| 401 unauthorized | Not a site secret key. |
| 403 domain_not_allowed | The URL's host isn't one of the website's domains. |
Crawler types are ai-training, ai-search, ai-assistant, search-engine, seo, social-preview and other. Requests for robots.txt, llms.txt, llms-full.txt, sitemaps and Markdown files are also counted as special files. Crawler requests are metered separately from events and are never refused for plan limits.
Details
- Responses for people (/stats/visitors, /stats/journeys, /visitors/…, realtime, settings and segments) are sent with
Cache-Control: private, no-store. - The dashboard calls the same endpoints with a session cookie. Cookie writes are accepted only from metricraven.com pages, so scripts should always use a key.
- Demo websites accept reads only; ingestion endpoints return 401 for them.
- Repeated payments with the same transaction ID are ignored, so a payment can be retried safely. Events and crawler requests are not deduplicated: retry them only when the request failed.