> ## Documentation Index
> Fetch the complete documentation index at: https://docs.clickbase.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Tracking & events

> The ingestion endpoints receive hits from the tracker (or any server-to-server sender).

The ingestion endpoints receive hits from the tracker (or any server-to-server sender). They do **not** use OAuth — they are authenticated by the site's **tracking key** (`tracking_key`, a UUID) sent in the `key` body field.

A hit is validated, then **queued** for processing, so a successful call returns `202 Accepted` with an empty body. An unknown `key` returns `404 Not Found`. All ingestion endpoints accept a `text/plain` body (for `navigator.sendBeacon`) as well as JSON.

Base URL: `https://clickbase.so/api`.

### Collect a pageview

```http theme={null}
POST /api/collect
```

Record a pageview. Rate limit: 600/min per IP.

| Parameter         | Type          | Required | Description                                                                   |
| ----------------- | ------------- | -------- | ----------------------------------------------------------------------------- |
| `key`             | string (uuid) | Yes      | The site's tracking key.                                                      |
| `hostname`        | string        | Yes      | Max 255 chars.                                                                |
| `url.path`        | string        | Yes      | Max 2048 chars.                                                               |
| `url.title`       | string        | No       | Max 512 chars.                                                                |
| `properties`      | object        | No       | Custom property map. Max 50 keys (key ≤ 64 chars, scalar values ≤ 500 chars). |
| `referrer`        | string        | No       | Max 2048 chars.                                                               |
| `screen.width`    | int           | No       | 0–65535.                                                                      |
| `screen.height`   | int           | No       | 0–65535.                                                                      |
| `language`        | string        | No       | Max 35 chars.                                                                 |
| `os`              | string        | No       | Max 50 chars.                                                                 |
| `os_version`      | string        | No       | Max 50 chars.                                                                 |
| `browser.name`    | string        | No       | Max 50 chars.                                                                 |
| `browser.version` | string        | No       | Max 50 chars.                                                                 |
| `device`          | string        | No       | One of `desktop`, `mobile`, `tablet`.                                         |
| `visitor_id`      | string (uuid) | No       | Client-supplied visitor id (cookieless mode).                                 |

Status: `202 Accepted` (`404` on unknown key).

```bash theme={null}
curl -X POST https://clickbase.so/api/collect \
  -H "Content-Type: application/json" \
  -d '{
    "key": "{tracking_key}",
    "hostname": "example.com",
    "url": { "path": "/pricing", "title": "Pricing" },
    "referrer": "https://google.com"
  }'
```

### Record a custom event

```http theme={null}
POST /api/event
```

Record a named custom event, optionally carrying revenue. Rate limit: 600/min per IP.

Revenue sent here is **reported**, not verified: it counts against a matching revenue goal for attribution, but it never reaches MRR or the Revenue page. It can never attribute under the reserved names (`payment`, the `subscription_*` names) that only Clickbase writes, since no goal may claim those names. See [Track revenue](/track-revenue) for the difference and for sending **verified** revenue via the Payments API below.

| Parameter                          | Type          | Required | Description                                                                                                                                              |
| ---------------------------------- | ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `key`                              | string (uuid) | Yes      | The site's tracking key.                                                                                                                                 |
| `hostname`                         | string        | Yes      | Max 255 chars.                                                                                                                                           |
| `name`                             | string        | Yes      | Event name. Max 255 chars.                                                                                                                               |
| `properties`                       | object        | No       | Custom property map (same limits as `/collect`).                                                                                                         |
| `url.path`                         | string        | No       | Max 2048 chars.                                                                                                                                          |
| `url.title`                        | string        | No       | Max 512 chars.                                                                                                                                           |
| `referrer`                         | string        | No       | Max 2048 chars.                                                                                                                                          |
| `screen.width` / `screen.height`   | int           | No       | 0–65535.                                                                                                                                                 |
| `language` / `os` / `os_version`   | string        | No       | Device context (same limits as `/collect`).                                                                                                              |
| `browser.name` / `browser.version` | string        | No       | Max 50 chars.                                                                                                                                            |
| `device`                           | string        | No       | `desktop`, `mobile`, or `tablet`.                                                                                                                        |
| `visitor_id`                       | string (uuid) | No       | Client-supplied visitor id.                                                                                                                              |
| `revenue.amount`                   | number        | No       | `> 0`. The tracker sends this under the wire field `$`; direct callers may send `revenue`. A malformed revenue shape is silently dropped, never a `422`. |
| `revenue.currency`                 | string        | No       | 3-letter ISO 4217 code. Required with `revenue`.                                                                                                         |

Status: `202 Accepted` (`404` on unknown key).

### Send an engagement ping

```http theme={null}
POST /api/engage
```

Record a scroll-depth / engaged-time delta for an existing pageview. Rate limit: 600/min per IP (its own bucket).

| Parameter    | Type          | Required | Description                                              |
| ------------ | ------------- | -------- | -------------------------------------------------------- |
| `key`        | string (uuid) | Yes      | The site's tracking key.                                 |
| `hostname`   | string        | Yes      | Max 255 chars.                                           |
| `url.path`   | string        | Yes      | Max 2048 chars.                                          |
| `url.title`  | string        | No       | Max 512 chars.                                           |
| `sd`         | int           | Yes      | Scroll depth 0–100. A value above 100 is clamped to 100. |
| `time`       | int           | Yes      | Engaged time (ms), 0 up to 4294967295.                   |
| `visitor_id` | string (uuid) | No       | Client-supplied visitor id.                              |

Status: `202 Accepted` (`404` on unknown key).

### Identify a visitor

```http theme={null}
POST /api/identify
```

Attach a user identity to the visitor's active session. Rate limit: 120/min, keyed by tracking key + IP (this endpoint can grow the `site_users` table, so it has a tighter bucket).

| Parameter    | Type          | Required | Description                                                                |
| ------------ | ------------- | -------- | -------------------------------------------------------------------------- |
| `key`        | string (uuid) | Yes      | The site's tracking key.                                                   |
| `hostname`   | string        | Yes      | Max 255 chars.                                                             |
| `identifier` | string        | Yes      | Your stable user identifier. Max 255 chars.                                |
| `name`       | string        | No       | Display name. Max 255 chars.                                               |
| `avatar`     | string (url)  | No       | Max 255 chars.                                                             |
| `custom`     | object        | No       | Custom trait map. Max 50 keys (key ≤ 64 chars, scalar values ≤ 500 chars). |
| `visitor_id` | string (uuid) | No       | Client-supplied visitor id.                                                |

Status: `202 Accepted` (`404` on unknown key).

## Payments API

The Payments API records and deletes verified revenue server-to-server. It uses the same **Passport personal access token** as the rest of the authenticated API — not the tracking key. Create a token on the **Developers** settings page or via [`POST /api/tokens`](/api/tokens); optionally limit it to specific sites with `site_ids`. See [Authentication](/api/authentication).

```http theme={null}
Authorization: Bearer {token}
```

Requires a workspace **Admin or Owner** (`SitePolicy::manage`) and an **active subscription** on the token's workspace. A missing/invalid token returns `401`; a member without manage access returns `403`; a lapsed subscription returns `402`. Rate limit: 60/min (same bucket as the authenticated API group).

`{siteKey}` is the site's **UUID** or **domain** (a domain segment may contain dots).

### Record a payment

```http theme={null}
POST /api/sites/{siteKey}/payments
```

Idempotent on `transaction_id`: a replay returns the existing record with `200` instead of creating a duplicate.

| Parameter        | Type          | Required | Description                                                                               |
| ---------------- | ------------- | -------- | ----------------------------------------------------------------------------------------- |
| `amount`         | int           | Yes      | Integer minor units (cents). `> 0`. `$49.90` → `4990`.                                    |
| `currency`       | string        | Yes      | 3-letter code. Must match the site's reporting currency (enforced by `RecordPayment`).    |
| `transaction_id` | string        | Yes      | Idempotency key. Max 255 chars.                                                           |
| `visitor_id`     | string (uuid) | No       | Visitor the payment is attributed to.                                                     |
| `session_id`     | string (uuid) | No       | Optional Clickbase session id (`clickbase_session_id` metadata). Visitor remains primary. |
| `email`          | string        | No       | Max 255 chars.                                                                            |
| `name`           | string        | No       | Max 255 chars.                                                                            |
| `customer_id`    | string        | No       | Max 255 chars.                                                                            |
| `renewal`        | bool          | No       | Whether this is a renewal.                                                                |
| `refunded`       | bool          | No       | Whether the payment was refunded.                                                         |
| `is_free_trial`  | bool          | No       | Whether this is a free-trial conversion.                                                  |
| `recurring`      | bool          | No       | Whether this payment is recurring.                                                        |
| `timestamp`      | string (date) | No       | Payment time; defaults to now.                                                            |

Response: `{ "message": ..., "transaction_id": ... }`. Status: `201 Created` on a new record, `200 OK` on a replay.

```bash theme={null}
curl -X POST https://clickbase.so/api/sites/example.com/payments \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"amount": 4990, "currency": "USD", "transaction_id": "ch_123"}'
```

### Delete a payment

```http theme={null}
DELETE /api/sites/{siteKey}/payments
```

Delete an API-recorded payment and its revenue row by `transaction_id`. Only deletes payments created through this API — never Stripe-ingested rows.

| Parameter        | Type   | Required | Description                   |
| ---------------- | ------ | -------- | ----------------------------- |
| `transaction_id` | string | Yes      | The transaction id to delete. |

Response: `200 OK` (`{ "message": "Payment deleted." }`), or `404 Not Found` when no matching payment exists.

```bash theme={null}
curl -X DELETE https://clickbase.so/api/sites/example.com/payments \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"transaction_id": "ch_123"}'
```

## Stripe webhook

```http theme={null}
POST /api/stripe/webhook/{siteId}
```

Per-site Stripe webhook receiver. `{siteId}` must be a site UUID. The request is authenticated by verifying the `Stripe-Signature` header against the site's configured webhook secret — a missing integration/secret returns `404`, a bad signature returns `400`. On success it dispatches to `HandleStripeWebhook` and returns `200 OK`. Rate limit: 600/min. This endpoint is configured in the site's Stripe integration, not called by hand.
