REST API
Tracking & events
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
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).
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
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 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
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
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; optionally limit it to specific sites with site_ids. See Authentication.
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
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.
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
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.
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
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.