# Quickstart

Three ways to send events: `curl` (or any HTTP client), the browser SDK, the Node SDK, or an AI agent via MCP. They all hit the same API.

## 1. Get an API key

In the dashboard, create a project. You'll get three keys:

| Key         | Use it from                        | What it can do |
| ----------- | ---------------------------------- | -------------- |
| `pk_live_…` | browsers (origin-restricted)       | ingest only    |
| `sk_live_…` | servers, scripts, anywhere private | ingest only    |
| `rk_live_…` | servers, MCP clients, dashboards   | read only      |

Add your site's origin to the project's allowlist before using `pk_*` keys from a browser.

## 2. Send your first event

### curl

```bash
curl -X POST https://api.millimetric.ai/v1/track \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "event": "signup",
    "anonymous_id": "u_abc",
    "user_id": "user_42",
    "url": "https://yoursite.com/?utm_source=facebook&utm_medium=cpc",
    "properties": { "plan": "free" }
  }'
```

### Browser — snippet (any HTML page)

```html
<script async src="https://cdn.millimetric.ai/v1/a.js"
        data-key="pk_live_…"></script>
<script>
  // optional: track a custom event
  window.mm?.track("clicked_pricing", { plan: "pro" });
</script>
```

What you get automatically:

* `$pageview` on load and every SPA route change
* `anonymous_id` in `localStorage` (no cookies)
* Captures `utm_*`, `fbclid`, `gclid`, `ttclid`, `msclkid`, `li_fat_id`, viewport, language, timezone
* Respects DNT / Global Privacy Control
* Batches events; flushes on `pagehide` via `sendBeacon`

### Browser — npm (React / Next / Vue / Svelte)

```bash
npm i @millimetric/track
```

```ts
import { init, track, identify, page } from "@millimetric/track";

init({ key: "pk_live_…" });
track("signup", { plan: "free" });
identify(user.id, { email: user.email });
```

### Node / Bun

```bash
npm i @millimetric/track-node
```

```ts
import { init, track, flush } from "@millimetric/track-node";

init({ key: "sk_live_…", host: "https://api.millimetric.ai" });
track({ event: "purchase", anonymous_id: req.cookies.aid, user_id: user.id,
        properties: { amount_cents: 4900 } });
// at the end of a serverless handler:
await flush();
```

### AI agent via MCP

Point any MCP-speaking agent at `https://api.millimetric.ai/mcp` with a Bearer token. **Only server-side keys** are accepted — `pk_*` is rejected because it's designed to ship in browser JS. Tools available:

* `track_event` (requires an `sk_*` or `admin` key)
* `query_events`, `get_stats`, `top_sources` (`rk_*`)

Example tool call:

```json
{ "name": "top_sources",
  "arguments": { "from": "2026-05-01T00:00:00Z", "to": "2026-05-16T00:00:00Z",
                 "breakdown": "source_medium" } }
```

## 3. Query your data

```bash
# Source/medium breakdown (this is what makes FB social vs paid show up)
curl "https://api.millimetric.ai/v1/sources?from=2026-05-01&to=2026-05-16&breakdown=source_medium" \
  -H "Authorization: Bearer rk_live_…"

# Aggregate stats
curl "https://api.millimetric.ai/v1/stats?metric=count&from=2026-05-01&to=2026-05-16&event=signup&group_by=source,medium&interval=day" \
  -H "Authorization: Bearer rk_live_…"

# Raw events
curl "https://api.millimetric.ai/v1/query?from=2026-05-01&to=2026-05-16&event=signup&limit=100" \
  -H "Authorization: Bearer rk_live_…"
```

## 4. Privacy operations

```bash
# Forget every event for a user (GDPR delete)
curl -X POST https://api.millimetric.ai/v1/forget \
  -H "Authorization: Bearer sk_live_…" \
  -d '{"user_id":"user_42"}'

# Bind an anonymous id to a user id
curl -X POST https://api.millimetric.ai/v1/identify \
  -H "Authorization: Bearer sk_live_…" \
  -d '{"anonymous_id":"u_abc","user_id":"user_42","traits":{"plan":"pro"}}'
```

## How attribution is classified

Every event runs through a server-side classifier that turns raw `utm_*`, click IDs, and referrer into a clean `(source, medium, confidence)` tuple. The rules cascade, first match wins:

1. `gclid`/`msclkid`/`ttclid`/`li_fat_id` ⇒ network / paid / **high**.
2. `fbclid` arriving via `l.facebook.com` or `lm.facebook.com` ⇒ facebook / paid / **high** (Meta's ad-redirect hosts).
3. `fbclid` + `utm_source=facebook|instagram|meta` ⇒ facebook|instagram / paid / **high**.
4. `utm_medium=cpc|paid|paid_social|cpm|display|retargeting` ⇒ paid / **high**.
5. `fbclid` alone, no other context ⇒ facebook / paid / **medium** (`fbclid` can leak onto organic shares but the dominant case is ad clicks).
6. Explicit `utm_source` with no paid signal ⇒ source / utm\_medium / **high**.
7. Referrer ∈ Facebook hosts without `fbclid` ⇒ facebook / **social** / medium.
8. Other known social referrers (twitter, linkedin, reddit, tiktok, youtube, pinterest, …) ⇒ source / social / medium.
9. Search engines (google.\*, bing, duckduckgo, …) ⇒ source / organic / medium.
10. Email clients / ESPs ⇒ email / email / medium.
11. Same-host referrer ⇒ internal / direct / high.
12. No referrer & no UTM & no click ID ⇒ direct / direct / high.
13. Otherwise ⇒ slug of referrer host / referral / **low**.

The matching rule's id is stored on every event so you can audit or re-classify later.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.millimetric.ai/quickstart.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
