# API overview

> Base URL, which key to use for each endpoint, the site parameter, response and error formats, rate limits, pagination and date ranges.

Source: https://metricraven.com/docs/api-overview  
Markdown: https://metricraven.com/docs/api-overview.md  
Section: API reference

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](https://metricraven.com/docs/cli) and the [MCP server](https://metricraven.com/docs/mcp) 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`.

```bash
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](https://metricraven.com/docs/api-authentication).

| 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_ID` on every website endpoint. A missing, repeated or unknown `site`, or a website the token is limited away from, returns 401.
- **Site secret keys** already identify their website, so `site` is 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](https://metricraven.com/docs/account-api#list-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](https://metricraven.com/docs/server-events) |
| POST /identify | [Identify users](https://metricraven.com/docs/identify-users#server) |
| POST /payments | [Payments API](https://metricraven.com/docs/payments-api) |
| POST /crawls | [Crawler requests (below)](https://metricraven.com/docs/api-overview#crawls) |
| POST /collect | The browser script and SDKs; no key, checked against your domains and app IDs. See [Proxy](https://metricraven.com/docs/proxy). |

### Reports

| Request | Access | Reference |
| --- | --- | --- |
| GET /stats/traffic | read | [Traffic](https://metricraven.com/docs/reports-api#traffic) |
| GET /stats/breakdown | read | [Breakdown](https://metricraven.com/docs/reports-api#breakdown) |
| GET /stats/filter-values | read | [Filter values](https://metricraven.com/docs/reports-api#filter-values) |
| GET /stats/conversions | read | [Conversions and funnels](https://metricraven.com/docs/reports-api#conversions) |
| GET /stats/goal | read | [One goal](https://metricraven.com/docs/reports-api#goal) |
| GET /stats/insights | read | [Buyer insights](https://metricraven.com/docs/reports-api#insights) |
| GET /stats/revenue | read | [Revenue](https://metricraven.com/docs/reports-api#revenue) |
| GET /stats/subscriptions | read | [Subscriptions](https://metricraven.com/docs/reports-api#subscriptions) |
| GET /stats/search | read | [Search Console](https://metricraven.com/docs/reports-api#search) |
| GET /stats/ads | read | [Ad spend and ROAS, every network](https://metricraven.com/docs/reports-api#ads) |
| GET /stats/meta-ads | read | [Meta Ads only (alias)](https://metricraven.com/docs/reports-api#meta-ads) |
| GET /stats/currencies | read | [Reporting currency and exchange rates](https://metricraven.com/docs/reports-api#endpoints) |
| GET /stats/crawlers | read | [Crawlers](https://metricraven.com/docs/reports-api#crawlers) |
| GET /stats/crawler-pages | read | [Crawled pages search](https://metricraven.com/docs/reports-api#crawler-pages) |
| GET /stats/x-referrers | read | [X links](https://metricraven.com/docs/reports-api#x-referrers) |
| GET /stats/mentions | read | [Social mentions](https://metricraven.com/docs/reports-api#mentions) |
| GET /stats/ai-visibility | read | [AI visibility](https://metricraven.com/docs/reports-api#ai-visibility) |
| GET /stats/overview | read | [Compact overview](https://metricraven.com/docs/reports-api#overview) |
| GET /stats/live | live | [Realtime](https://metricraven.com/docs/reports-api#live) |
| GET /stats/live/replay | live | [Realtime replay](https://metricraven.com/docs/reports-api#live-replay) |
| GET /stats/live/value | live | [Value of visitors online](https://metricraven.com/docs/reports-api#live-value) |
| GET /stats/visitors | private | [Visitor search](https://metricraven.com/docs/reports-api#visitors) |
| GET /stats/journeys | private | [Journeys](https://metricraven.com/docs/reports-api#journeys) |

### Website configuration and people

| Request | Access | Reference |
| --- | --- | --- |
| GET /notes | live | [Chart notes](https://metricraven.com/docs/site-api#notes) |
| POST /notes, PUT /notes/ID, DELETE /notes/ID | write | [Chart notes](https://metricraven.com/docs/site-api#notes) |
| GET /commits | live | [GitHub commits](https://metricraven.com/docs/site-api#commits) |
| GET /funnels | read | [Funnels](https://metricraven.com/docs/site-api#funnels) |
| POST /funnels, PUT /funnels/ID, DELETE /funnels/ID | write | [Funnels](https://metricraven.com/docs/site-api#funnels) |
| GET /segments | private | [Segments](https://metricraven.com/docs/site-api#segments) |
| POST /segments, PUT /segments/ID, DELETE /segments/ID | write | [Segments](https://metricraven.com/docs/site-api#segments) |
| GET /site | private | [Settings](https://metricraven.com/docs/site-api#settings) |
| PUT /site | write | [Settings](https://metricraven.com/docs/site-api#settings) |
| GET, POST /site/keys; PATCH, DELETE /site/keys/ID; POST /site/keys/ID/roll | write, no secret key | [Secret keys](https://metricraven.com/docs/site-api#secret-keys) |
| GET /goals/customizations | read, no share links | [Goal names and colours](https://metricraven.com/docs/goals-funnels#customize-goals) |
| PUT, DELETE /goals/customizations | write | [Goal names and colours](https://metricraven.com/docs/goals-funnels#customize-goals) |
| GET /visitors/VISITOR_ID | private | [Visitor profile](https://metricraven.com/docs/visitors-api#profile) |
| DELETE /people | write, no tokens | [Erase a person](https://metricraven.com/docs/visitors-api#erase) |
| DELETE /payments | write | [Delete payments](https://metricraven.com/docs/payments-api#delete) |
| DELETE /events | write | [Delete goal events](https://metricraven.com/docs/server-events#delete) |
| GET, PUT, PATCH /bot-traffic/settings; GET, POST, PUT, DELETE /bot-traffic/token; GET /bot-traffic/usage | read / write, account token | [Bot traffic settings](https://metricraven.com/docs/bot-traffic-settings#api) |
| GET, POST, DELETE /managed-proxy; POST /managed-proxy/check; GET /managed-proxy/dns-provider | read / write, account token | [Managed proxy](https://metricraven.com/docs/managed-proxy#api) |
| GET, POST /alerts; GET, PUT, DELETE /alerts/ID; GET /alerts/history | read / write, no share links | [Conversion alerts](https://metricraven.com/docs/goal-alerts#api) |
| GET, PUT /notifications | token or dashboard only | [Email preferences](https://metricraven.com/docs/email-reports#api) |

### Account (account tokens only)

| Request | Reference |
| --- | --- |
| GET, PATCH /account | [Account API](https://metricraven.com/docs/account-api#endpoints) |
| GET, POST /websites | [Websites](https://metricraven.com/docs/account-api#list-websites) |
| GET, PATCH, DELETE /websites/ID | [Update or delete a website](https://metricraven.com/docs/account-api#update-website) |
| GET, POST /tokens; DELETE /tokens/ID | [Access tokens](https://metricraven.com/docs/account-api#tokens) |
| GET, POST /members; PATCH, DELETE /members/USER_ID; POST, DELETE /members/invites/ID | [Team members](https://metricraven.com/docs/account-api#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 `null` when 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.

```json title="400 response"
{
  "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.

```bash
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](https://metricraven.com/docs/reports-api#crawlers). Ready-made middleware is in [Bots and AI crawlers](https://metricraven.com/docs/bots-ai-crawlers).

```bash
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.

> **Warning:** Keys belong on your server. Never put a site secret key or an access token in browser code, a mobile app, a public repository or a URL.

## 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.
