API reference
Read analytics, push the tracking plan (analytics.yaml), and send server-side events.
- Base URL:
https://twelvebit.app/api/v1 - OpenAPI 3.1: https://twelvebit.app/api/v1/openapi.json (version 1.0.0)
Authentication#
Send a key in the Authorization header:
curl -sS https://twelvebit.app/api/v1/overview -H "Authorization: Bearer $TWELVEBIT_API_KEY"| Credential | Prefix | Scope |
|---|---|---|
| Site key | tbk_ | One site. The site parameter is ignored. Create it in the site settings, or let twelvebit init create it. |
| Account token | tbt_ | Every site you can open. Pass ?site=<id, public id or domain> (or site_id in the payments body). Create it on your account page. |
| Session | cookie or Bearer session token | The dashboard session, and the token that twelvebit init gets through the device login. Works like an account token. |
Keys are secrets. Use them on servers and in terminals only, never in browser code. Viewers can read; writing (events, identify, payments, tracking plan, annotations, bots) needs a site key or the owner or member role.
Responses#
Success: { "data": …, "meta": { … } }. meta names the site and, for analytics, the time range (range.label, range.from, range.to, range.tz) and the attribution model (last touch: the visit before the payment).
Error: { "error": { "code": "site_required", "message": "…" } } with a matching HTTP status (400, 401, 403, 404, 422, 429, 500). Messages say what to do next.
Rate limit#
120 requests per minute per key. Above that the API answers 429 with a Retry-After header in seconds. Wait that long, then try again.
Common query parameters#
| Parameter | Values | Notes |
|---|---|---|
period | today, yesterday, 24h, 7d, 30d, 90d, 12m, wtd, mtd, ytd, all, custom | Default 30d. Days are in the site's time zone. |
from, to | YYYY-MM-DD | Both together make a custom range. to is included. |
f_<dim> | any value | Filter, for example f_country=DE, f_channel=Organic Search, f_page=/pricing, f_goal=signup. Dimensions: channel, referrer, campaign, keyword, source, hostname, entry, exit, country, region, city, browser, os, device, page, goal. Filters combine with AND. |
site | id, public id or domain | Needed for account tokens and sessions when you have more than one site. |
Revenue in breakdowns is attributed with the model last touch: the visit before the payment.
Endpoints#
| Method | Path | Summary |
|---|---|---|
GET | /api/v1/sites | List sites |
GET | /api/v1/sites/{siteId} | Get a site |
GET | /api/v1/overview | KPIs for a range |
GET | /api/v1/timeseries | Visitors and revenue over time |
GET | /api/v1/breakdown | Top values of one dimension |
GET | /api/v1/realtime | Who is on the site now |
GET | /api/v1/goals | Goals and their completions |
GET | /api/v1/funnels | Compute a funnel |
GET | /api/v1/people | List visitors |
GET | /api/v1/people/{visitorId} | One visitor's journey |
GET | /api/v1/tracking-plan | Get the tracking plan |
PUT | /api/v1/tracking-plan | Replace the tracking plan |
GET | /api/v1/install-check | Install check and drift |
GET | /api/v1/annotations | List annotations |
POST | /api/v1/annotations | Add an annotation |
POST | /api/v1/events | Send a goal from your server |
POST | /api/v1/identify | Identify a visitor from your server |
POST | /api/v1/payments | Record a payment |
GET | /api/v1/bots | Crawler traffic |
POST | /api/v1/bots | Record a crawler hit |
POST | /api/v1/cli/bootstrap | Find or create a site and mint a key (CLI) |
GET | /api/v1/openapi.json | This document |
GET /api/v1/sites#
List sites.
Every site the key can read. A site key returns only its own site.
curl -sS "https://twelvebit.app/api/v1/sites" -H "Authorization: Bearer $TWELVEBIT_API_KEY"Responses: 200 OK · 401 Missing or invalid key · 429 Rate limited (see Retry-After).
GET /api/v1/sites/{siteId}#
Get a site.
One site by id, public id or domain, with its script tag.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
siteId | path | string | yes | Site id, public id (tb_…) or domain. |
curl -sS "https://twelvebit.app/api/v1/sites/tb_YOUR_SITE_ID" -H "Authorization: Bearer $TWELVEBIT_API_KEY"Responses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 404 Not found · 429 Rate limited (see Retry-After).
GET /api/v1/overview#
KPIs for a range.
Visitors, visits, page views, bounce rate, time on site, revenue, customers and conversion, for the range and the previous range of the same length, plus the number of people online now.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
period | query | today | yesterday | 24h | 7d | 30d | 90d | 6m | 12m | wtd | mtd | ytd | all | custom | no | |
from | query | string | no | First day (YYYY-MM-DD, site time zone). Use with to. |
to | query | string | no | Last day, inclusive. |
f_<dim> | query | string | no | Filter by one value. Dimensions: channel, referrer, campaign, keyword, source, hostname, entry, exit, country, region, city, browser, os, device, page, goal. |
curl -sS "https://twelvebit.app/api/v1/overview?period=7d" -H "Authorization: Bearer $TWELVEBIT_API_KEY"Responses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 404 Not found · 429 Rate limited (see Retry-After).
GET /api/v1/timeseries#
Visitors and revenue over time.
One point per hour, day, week or month in the site's time zone.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
period | query | today | yesterday | 24h | 7d | 30d | 90d | 6m | 12m | wtd | mtd | ytd | all | custom | no | |
from | query | string | no | First day (YYYY-MM-DD, site time zone). Use with to. |
to | query | string | no | Last day, inclusive. |
g | query | hour | day | week | month | no | Bucket size. Default depends on the range length. |
f_<dim> | query | string | no | Filter by one value. Dimensions: channel, referrer, campaign, keyword, source, hostname, entry, exit, country, region, city, browser, os, device, page, goal. |
curl -sS "https://twelvebit.app/api/v1/timeseries?period=7d" -H "Authorization: Bearer $TWELVEBIT_API_KEY"Responses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 404 Not found · 429 Rate limited (see Retry-After).
GET /api/v1/breakdown#
Top values of one dimension.
Visitors and attributed revenue (last touch: the visit before the payment) per value, sorted by visitors. dim=goal adds completions; dim=referrer adds the channel; dim=region and dim=city add the country.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
period | query | today | yesterday | 24h | 7d | 30d | 90d | 6m | 12m | wtd | mtd | ytd | all | custom | no | |
from | query | string | no | First day (YYYY-MM-DD, site time zone). Use with to. |
to | query | string | no | Last day, inclusive. |
dim | query | channel | referrer | campaign | keyword | source | hostname | entry | exit | country | region | city | browser | os | device | page | goal | outbound | no | |
limit | query | integer | no | |
f_<dim> | query | string | no | Filter by one value. Dimensions: channel, referrer, campaign, keyword, source, hostname, entry, exit, country, region, city, browser, os, device, page, goal. |
curl -sS "https://twelvebit.app/api/v1/breakdown?period=7d" -H "Authorization: Bearer $TWELVEBIT_API_KEY"Responses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 404 Not found · 429 Rate limited (see Retry-After).
GET /api/v1/realtime#
Who is on the site now.
People active in the last 5 minutes (with page, source, place and goals), visitors per minute for the last 30 minutes (oldest first), and the last 30 minutes of events and payments.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
curl -sS "https://twelvebit.app/api/v1/realtime" -H "Authorization: Bearer $TWELVEBIT_API_KEY"Responses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 404 Not found · 429 Rate limited (see Retry-After).
GET /api/v1/goals#
Goals and their completions.
Visitors, completions and revenue of those visitors per goal. declared says whether the goal is in the tracking plan; undeclared and not_seen show drift.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
period | query | today | yesterday | 24h | 7d | 30d | 90d | 6m | 12m | wtd | mtd | ytd | all | custom | no | |
from | query | string | no | First day (YYYY-MM-DD, site time zone). Use with to. |
to | query | string | no | Last day, inclusive. |
f_<dim> | query | string | no | Filter by one value. Dimensions: channel, referrer, campaign, keyword, source, hostname, entry, exit, country, region, city, browser, os, device, page, goal. |
curl -sS "https://twelvebit.app/api/v1/goals?period=7d" -H "Authorization: Bearer $TWELVEBIT_API_KEY"Responses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 404 Not found · 429 Rate limited (see Retry-After).
GET /api/v1/funnels#
Compute a funnel.
With steps, computes that funnel: each step counts visitors who reached it after the step before. Without steps, computes every funnel saved in the dashboard and every funnel in the tracking plan (name picks one).
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
period | query | today | yesterday | 24h | 7d | 30d | 90d | 6m | 12m | wtd | mtd | ytd | all | custom | no | |
from | query | string | no | First day (YYYY-MM-DD, site time zone). Use with to. |
to | query | string | no | Last day, inclusive. |
steps | query | string | no | 2 to 8 comma-separated steps: page:/path (use * as a wildcard) or goal:name (a bare name is a goal). |
name | query | string | no | Name of a saved or planned funnel. |
f_<dim> | query | string | no | Filter by one value. Dimensions: channel, referrer, campaign, keyword, source, hostname, entry, exit, country, region, city, browser, os, device, page, goal. |
curl -sS "https://twelvebit.app/api/v1/funnels?period=7d" -H "Authorization: Bearer $TWELVEBIT_API_KEY"Responses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 404 Not found · 429 Rate limited (see Retry-After).
GET /api/v1/people#
List visitors.
Visitors seen in the range, newest first or by revenue. Anonymous visitors get a stable friendly name like amber-fox-4821.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
period | query | today | yesterday | 24h | 7d | 30d | 90d | 6m | 12m | wtd | mtd | ytd | all | custom | no | |
from | query | string | no | First day (YYYY-MM-DD, site time zone). Use with to. |
to | query | string | no | Last day, inclusive. |
filter | query | all | customers | identified | no | |
q | query | string | no | Search email or name (contains), or an exact visitor id or user id. |
sort | query | recent | revenue | no | |
limit | query | integer | no | |
offset | query | integer | no |
curl -sS "https://twelvebit.app/api/v1/people?period=7d" -H "Authorization: Bearer $TWELVEBIT_API_KEY"Responses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 404 Not found · 429 Rate limited (see Retry-After).
GET /api/v1/people/{visitorId}#
One visitor's journey.
Profile, attribution (first touch and the credited visit: last touch: the visit before the payment), every visit with its events, and payments.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
visitorId | path | string | yes | Visitor id (_tb_vid) or the user_id from identify. |
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
curl -sS "https://twelvebit.app/api/v1/people/VISITOR_ID" -H "Authorization: Bearer $TWELVEBIT_API_KEY"Responses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 404 Not found · 429 Rate limited (see Retry-After).
GET /api/v1/tracking-plan#
Get the tracking plan.
The stored plan as JSON and YAML. Send Accept: text/yaml (or ?format=yaml) to get only the YAML text. The YAML is rebuilt from the stored plan, so comments are not kept.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
format | query | json | yaml | no |
curl -sS "https://twelvebit.app/api/v1/tracking-plan" -H "Authorization: Bearer $TWELVEBIT_API_KEY"Responses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 404 Not found · 429 Rate limited (see Retry-After).
PUT /api/v1/tracking-plan#
Replace the tracking plan.
Send analytics.yaml as the body (Content-Type: text/yaml), or the same plan as JSON. The schema is strict: unknown keys are errors. The response lists added, removed and changed events. ?dry_run=1 validates without saving.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
dry_run | query | boolean | no |
Request body:
version: 1
project: example.com
events:
signup:
description: A visitor creates an account
props:
plan: { type: string, enum: [free, pro] }curl -sS -X PUT "https://twelvebit.app/api/v1/tracking-plan" -H "Authorization: Bearer $TWELVEBIT_API_KEY" \
-H "Content-Type: text/yaml" --data-binary @analytics.yamlResponses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 403 Not allowed for this key · 404 Not found · 422 Invalid tracking plan · 429 Rate limited (see Retry-After).
GET /api/v1/install-check#
Install check and drift.
What the site has sent: first and last event, the last 10 events, counts by type in the last 24 hours, host names seen, and for each event in the tracking plan whether it has been seen in the last 30 days. undeclared lists goals that were sent but are not in the plan. next_steps says what to fix.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
curl -sS "https://twelvebit.app/api/v1/install-check" -H "Authorization: Bearer $TWELVEBIT_API_KEY"Responses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 404 Not found · 429 Rate limited (see Retry-After).
GET /api/v1/annotations#
List annotations.
Notes shown on the time charts in the range.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
period | query | today | yesterday | 24h | 7d | 30d | 90d | 6m | 12m | wtd | mtd | ytd | all | custom | no | |
from | query | string | no | First day (YYYY-MM-DD, site time zone). Use with to. |
to | query | string | no | Last day, inclusive. |
curl -sS "https://twelvebit.app/api/v1/annotations?period=7d" -H "Authorization: Bearer $TWELVEBIT_API_KEY"Responses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 404 Not found · 429 Rate limited (see Retry-After).
POST /api/v1/annotations#
Add an annotation.
Mark a launch, a deploy or a price change on the charts. ts defaults to now.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
Request body:
{
"label": "Launched on Product Hunt",
"ts": "2026-10-01T09:00:00Z",
"url": "https://www.producthunt.com/posts/example"
}curl -sS -X POST "https://twelvebit.app/api/v1/annotations" -H "Authorization: Bearer $TWELVEBIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"label":"Launched on Product Hunt","ts":"2026-10-01T09:00:00Z","url":"https://www.producthunt.com/posts/example"}'Responses: 201 Created · 400 Invalid input · 401 Missing or invalid key · 403 Not allowed for this key · 404 Not found · 429 Rate limited (see Retry-After).
POST /api/v1/events#
Send a goal from your server.
Records a goal for a visitor that the browser script has already seen. Pass visitor_id (the _tb_vid cookie) or user_id (sent earlier with identify). The goal joins the visitor's latest visit. Names are lowercased; use snake_case.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
Request body:
{
"name": "subscription_started",
"user_id": "user_123",
"props": {
"plan": "pro"
}
}curl -sS -X POST "https://twelvebit.app/api/v1/events" -H "Authorization: Bearer $TWELVEBIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"subscription_started","user_id":"user_123","props":{"plan":"pro"}}'Responses: 202 Recorded · 400 Invalid input · 401 Missing or invalid key · 403 Not allowed for this key · 404 Not found · 429 Rate limited (see Retry-After).
POST /api/v1/identify#
Identify a visitor from your server.
Attaches your user id, email, name, avatar and traits to a visitor. Later server-side events can then use user_id.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
Request body:
{
"visitor_id": "k3j5h2g7f9d1s8a4q6w0e2r5",
"user_id": "user_123",
"email": "ada@example.com",
"name": "Ada",
"traits": {
"plan": "pro"
}
}curl -sS -X POST "https://twelvebit.app/api/v1/identify" -H "Authorization: Bearer $TWELVEBIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"visitor_id":"k3j5h2g7f9d1s8a4q6w0e2r5","user_id":"user_123","email":"ada@example.com","name":"Ada","traits":{"plan":"pro"}}'Responses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 403 Not allowed for this key · 404 Not found · 429 Rate limited (see Retry-After).
POST /api/v1/payments#
Record a payment.
For payment providers without a built-in connection. Safe to repeat: transaction_id makes it idempotent. The payment is credited to a visit (last touch: the visit before the payment) through visitor_id/session_id, or through the email or customer id of an identified visitor. An amount of 0 is a free trial and is not counted. Account tokens pass site_id in the body.
Request body:
{
"amount": 49,
"currency": "USD",
"transaction_id": "inv_1042",
"visitor_id": "k3j5h2g7f9d1s8a4q6w0e2r5",
"email": "ada@example.com",
"plan": "Pro"
}curl -sS -X POST "https://twelvebit.app/api/v1/payments" -H "Authorization: Bearer $TWELVEBIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"amount":49,"currency":"USD","transaction_id":"inv_1042","visitor_id":"k3j5h2g7f9d1s8a4q6w0e2r5","email":"ada@example.com","plan":"Pro"}'Responses: 200 Already recorded (duplicate transaction_id), or a free trial · 201 Recorded · 400 Invalid input · 401 Missing or invalid key · 403 Not allowed for this key · 404 Not found · 429 Rate limited (see Retry-After).
GET /api/v1/bots#
Crawler traffic.
Hits from AI and search crawlers in the range, by kind (ai_answer, indexing, training) and by bot.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
period | query | today | yesterday | 24h | 7d | 30d | 90d | 6m | 12m | wtd | mtd | ytd | all | custom | no | |
from | query | string | no | First day (YYYY-MM-DD, site time zone). Use with to. |
to | query | string | no | Last day, inclusive. |
curl -sS "https://twelvebit.app/api/v1/bots?period=7d" -H "Authorization: Bearer $TWELVEBIT_API_KEY"Responses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 404 Not found · 429 Rate limited (see Retry-After).
POST /api/v1/bots#
Record a crawler hit.
Crawlers do not run JavaScript, so your server reports them. Send the user agent and path of a request; known crawlers are stored as ai_answer (an assistant fetches the page for a person now), indexing (search engines) or training (model training). Unknown user agents are ignored. Fire and forget: do not make the page wait.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
site | query | string | no | Site id, public id (tb_…) or domain. Needed for account tokens with more than one site; site keys ignore it. |
Request body:
{
"user_agent": "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; ChatGPT-User/1.0; +https://openai.com/bot",
"path": "/pricing"
}curl -sS -X POST "https://twelvebit.app/api/v1/bots" -H "Authorization: Bearer $TWELVEBIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"user_agent":"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; ChatGPT-User/1.0; +https://openai.com/bot","path":"/pricing"}'Responses: 202 Accepted · 400 Invalid input · 401 Missing or invalid key · 403 Not allowed for this key · 404 Not found · 429 Rate limited (see Retry-After).
POST /api/v1/cli/bootstrap#
Find or create a site and mint a key (CLI).
Used by twelvebit init after the device sign-in. Needs a session (the device flow's access token as a Bearer). Finds the user's site for the domain, or creates it, and returns a new site key named after the machine.
Request body:
{
"domain": "example.com",
"timezone": "Europe/Berlin",
"hostname": "ada-mbp"
}curl -sS -X POST "https://twelvebit.app/api/v1/cli/bootstrap" -H "Authorization: Bearer $TWELVEBIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain":"example.com","timezone":"Europe/Berlin","hostname":"ada-mbp"}'Responses: 200 OK · 400 Invalid input · 401 Missing or invalid key · 429 Rate limited (see Retry-After).
GET /api/v1/openapi.json#
This document.
curl -sS "https://twelvebit.app/api/v1/openapi.json" -H "Authorization: Bearer $TWELVEBIT_API_KEY"Responses: 200 OpenAPI 3.1 document.