API
The v1 API exposes a set of read-only endpoints for your analytics data, each gated by an API key bound to your workspace. This page covers everything: which plan you need, creating a key, authentication, the shared parameters, all seven endpoints, errors, rate limits, and the llms.txt manifest.
The API is read-only: you use it to fetch your own analytics data, never to send data in.
Let an AI set this up for you
Copy the prompt below into Claude, ChatGPT or any other AI. It carries everything the AI needs: where to get your key, the base URL, the auth header, the parameters and every endpoint. It asks you for your key first, then writes and runs the requests.
I use TrueMetriks, a server-side tracking and conversion attribution platform.
Help me pull my own analytics out of it through its read-only REST API, and
then answer questions about that data.
BEFORE YOU WRITE ANY CODE, ask me for these two things and wait for my reply:
1. My TrueMetriks API key.
2. My site_id (a whole number).
Tell me exactly where to find them:
- Sign in at https://app.truemetriks.com
- Open "Settings" for the site you want (the site's OWN settings, NOT
Account Settings), then click the "Integrations" tab.
- In the tile grid, after "Webhooks", click the "API Keys" tile.
- Under "Create API key", type a name (for example "ai-assistant"), click
"Create", and copy the key from the dialog that appears.
- IMPORTANT: the key is shown ONCE and cannot be looked up again. Tell me to
paste it somewhere safe, such as a password manager, before closing the
dialog. If it is lost, the only fix is to create a new key.
- API access requires the Unlimited plan. If the API Keys tile is greyed out
with a padlock reading UNLIMITED, I am on a lower plan and cannot use the
API until I upgrade.
- My site_id is the number in the dashboard URL while that site is open, for
example https://app.truemetriks.com/42/main means site_id is 42. It is also
in the settings URL: /settings/websites/42/integrations.
Never print my key back to me in full, never paste it into a public place, and
never commit it to a repository. Read it from an environment variable such as
TM_API_KEY instead of hard coding it.
HOW THE API WORKS
Base URL: https://app.truemetriks.com/v1
Auth: send this header on every request
Authorization: Bearer <MY_API_KEY>
Method: every endpoint is GET and read-only. Responses are JSON.
Shared query parameters, accepted by every endpoint:
site_id REQUIRED. Whole number. My site.
period Optional shorthand. One of: today, yesterday, last_7d, last_30d,
last_90d, last_365d. If given, it overrides from/to.
from, to Optional explicit dates, YYYY-MM-DD, both or neither. Inclusive.
timezone Optional IANA timezone, for example America/New_York. Default UTC.
If neither period nor from/to is given, the range defaults to the last 30
days. The range may not exceed 366 days. There are NO start_date or end_date
parameters: sending them does nothing and you silently get the last 30 days.
There is no previous-period shortcut, so to compare two periods call the
endpoint twice with explicit from/to ranges.
All money fields come back as decimal dollars (for example 4590.50), never
cents, rounded to 2 decimal places.
THE SEVEN ENDPOINTS
GET /v1/overview
Top-level KPIs plus a per-source breakdown. The only endpoint that returns
per-source SESSION counts, so use it for revenue-per-session questions.
Extra params: none.
Returns: period{from,to,timezone},
totals{sessions,unique_visitors,pageviews,revenue,leads,purchases},
by_source[{source,channel,sessions,revenue,leads,purchases}]
GET /v1/revenue
Any "how much money" question.
Extra params: none.
Returns: period, totals{revenue,purchases,average_order_value},
by_source[{source,channel,revenue,purchases,conversion_rate_pct}],
by_product[{sku,product_name,revenue,units}],
by_day[{date,revenue,purchases}]
Note: conversion_rate_pct is sessions-to-purchase for that source, NOT
leads-to-purchase. For leads-to-purchase, divide /v1/revenue
totals.purchases by /v1/leads totals.leads.
GET /v1/leads
Lead counts with source attribution. This returns COUNTS, not a list of
people, and no personal data.
Extra params: none.
Returns: period, totals{leads}, by_source[{source,channel,leads}]
GET /v1/pages
Top pages by pageviews. No source breakdown, by design.
Extra params: limit (1 to 100, default 25).
Returns: period,
pages[{path,pageviews,unique_visitors,avg_time_on_page_seconds,
bounce_rate_pct}]
GET /v1/products
Per-product revenue and units.
Extra params: none.
Returns: period,
products[{sku,product_name,units_sold,revenue,average_price}],
by_source[{source,channel,top_product_sku,top_product_name,revenue}]
GET /v1/users
Visitor counts and segmentation. Aggregate counts only, not a list of people.
Extra params: none.
Returns: period,
totals{unique_visitors,returning_visitors,new_visitors},
by_source[{source,channel,visitors}],
by_country[{country,visitors}]
GET /v1/funnels
The site's saved funnels with per-step counts and conversion rates. The
funnels array is empty if none are defined.
Extra params: none.
Returns: period,
funnels[{id,name,overall_conversion_pct,
steps[{step_name,visitors,conversion_from_previous_pct}]}]
ERRORS TO EXPECT
401 AUTH_REQUIRED no Authorization header
401 INVALID_API_KEY key not found, expired or revoked
403 TIER_NO_API_ACCESS my plan does not include API access
403 SITE_ACCESS_DENIED key is valid but has no access to that site_id
400 MISSING_SITE_ID site_id was not supplied
400 BAD_DATE_FORMAT dates are not YYYY-MM-DD, or only one of from/to
400 RANGE_TOO_WIDE range is longer than 366 days
429 RATE_LIMITED 200 requests per minute per key was exceeded
504 QUERY_TIMEOUT query took over 10 seconds, narrow the range
WHAT TO DO
1. Ask me for the key and site_id, as described above.
2. Write a script (bash with curl, or Python with requests) that reads the key
from the TM_API_KEY environment variable.
3. Start with a single call to /v1/overview for period=last_7d to confirm the
key works, and show me the result.
4. Then ask what I actually want to know, and use the endpoints above to answer
it. If a question needs two date ranges, call the endpoint twice.
If you are in a chat-only tool with no way to run code or make HTTP requests,
say so, then give me a ready-to-run script I can run myself and paste the
output back to you.
You need the Unlimited plan
API access is on the Unlimited plan only. On Starter and Growth the API Keys tile is greyed out with a padlock chip reading UNLIMITED, so no key can be created.
MCP (AI access)
UNLIMITED
API Keys
UNLIMITED
If a workspace drops to a lower plan, its keys stay in place but every request is refused:
{
"error": "API access is available on the Unlimited plan. Please upgrade to use the API.",
"code": "TIER_NO_API_ACCESS"
}
Upgrading restores access immediately, with the same key.
Creating an API key
API keys live on the site's own Integrations tab. They are no longer in Account Settings.
- Open Settings for the site you want (the site's settings, not Account Settings).
- Click the Integrations tab.
- After Webhooks, click the API Keys tile. Its status line reads
No keys yet,1 keyorN keys.
Integrations
Connect third-party data sources to fire events into TrueMetriks.
Typeform
Connected
Calendly
Connected
Microsoft Clarity
Configured (1 project)
Stripe
Connected
Whop
Not connected
PayPal
Not connected
Webhooks
Receiving 4, sending 2
MCP (AI access)
No key yet
API Keys
No keys yet
- Type a name under Create API key and click Create. Name it after where it will be used, like
reporting-script, so you can revoke just that one later.
Back to Integrations
API Keys
Read your analytics from your own code over the v1 REST API.
Using the API
Endpoints, authentication and rate limits.
Create API key
Name it after where it will be used, so you can revoke just that one later.
Your API keys
The full key is shown once, in a dialog. Copy it then and store it somewhere safe. Afterwards the list keeps only a masked preview, and a lost key cannot be recovered: you have to create a new one.
API Key Created
Save this API key securely. You won't be able to see it again.
Your API Key
Click Delete next to a key to revoke it. Revocation is immediate and cannot be undone.
What the key list does not show
This list shows only the keys created on this page. Deliberately hidden: keys from the WordPress plugin (named wp-plugin...), the MCP key, and revoked keys.
Never delete a wp-plugin key. It would break that site's plugin. It is hidden here precisely so that cannot happen by accident.
Keys are scoped to one workspace and inherit your site access, so a key can only read sites you can already see.
Base URL
https://app.truemetriks.com/v1
There is no separate API hostname. Every endpoint sits under the same origin as the dashboard.
Authentication
Every request requires an Authorization header with your key as a Bearer token:
Authorization: Bearer YOUR_API_KEY
A missing or malformed header returns 401 AUTH_REQUIRED. A key that is unknown, expired or revoked returns 401 INVALID_API_KEY. A valid key asking for a site you cannot access returns 403 SITE_ACCESS_DENIED.
Keep the key out of your source code. Read it from an environment variable instead:
export TM_API_KEY="your_key_here"
curl -H "Authorization: Bearer $TM_API_KEY" \
"https://app.truemetriks.com/v1/overview?site_id=42&period=last_7d"
Common query parameters
Every endpoint accepts these:
| Param | Required | Description |
|---|---|---|
| site_id | yes | The site you are querying, as a whole number |
| period | no | today, yesterday, last_7d, last_30d, last_90d, last_365d. Overrides from/to |
| from | no | Start date, YYYY-MM-DD, inclusive. Must be paired with to |
| to | no | End date, YYYY-MM-DD, inclusive. Must be paired with from |
| timezone | no | IANA timezone for date bucketing, for example America/New_York. Default UTC |
Before your first request:
- There is no
start_dateorend_date. Sending them has no effect, and since the range is optional you get the default last 30 days back with no error to warn you. - Send neither
periodnorfrom/toand the range defaults to the last 30 days. fromandtocome as a pair. Sending one returns400 BAD_DATE_FORMAT.- The range may not exceed 366 days (
400 RANGE_TOO_WIDE), andfrommust not be later thanto(400 INVERTED_RANGE). - There is no previous-period shortcut. To compare two periods, call the endpoint twice.
Every response echoes the range it used, so you can confirm what you got:
"period": { "from": "2026-07-06", "to": "2026-08-05", "timezone": "UTC" }
Money and rounding
All monetary fields are returned as decimal dollars, for example 4590.50, never cents. Values are rounded to 2 decimal places on the server.
Caching
Responses are cached for 60 seconds per unique set of parameters. The X-Cache response header reads HIT or MISS. To force a fresh read, send Cache-Control: no-cache.
Endpoints
All seven endpoints are GET and read-only.
GET /v1/overview
Top-level KPIs for the period plus a per-source breakdown. This is the only endpoint that returns per-source session counts, so use it whenever you need revenue per session or sessions per lead.
Parameters: the common parameters only.
curl -H "Authorization: Bearer $TM_API_KEY" \
"https://app.truemetriks.com/v1/overview?site_id=42&period=last_7d"
{
"period": { "from": "2026-05-08", "to": "2026-05-15", "timezone": "UTC" },
"totals": {
"sessions": 4321,
"unique_visitors": 3210,
"pageviews": 12345,
"revenue": 4590.50,
"leads": 287,
"purchases": 32
},
"by_source": [
{ "source": "facebook", "channel": "Paid Social", "sessions": 2100, "revenue": 2750.00, "leads": 140, "purchases": 18 },
{ "source": "google", "channel": "Paid Search", "sessions": 1100, "revenue": 900.50, "leads": 70, "purchases": 9 }
]
}
channel is the marketing ecosystem the session was classified into at ingest, the same grouping the dashboard Main page uses.
GET /v1/revenue
Revenue totals with breakdowns by source, by product and by day. Use it for any "how much money" question.
Parameters: the common parameters only.
curl -H "Authorization: Bearer $TM_API_KEY" \
"https://app.truemetriks.com/v1/revenue?site_id=42&period=last_30d"
{
"period": { "from": "2026-04-15", "to": "2026-05-15", "timezone": "UTC" },
"totals": { "revenue": 23790.00, "purchases": 255, "average_order_value": 93.29 },
"by_source": [
{ "source": "facebook", "channel": "Paid Social", "revenue": 12450.00, "purchases": 134, "conversion_rate_pct": 4.2 }
],
"by_product": [
{ "sku": "TM-PRO-001", "product_name": "Premium Subscription", "revenue": 11900.00, "units": 100 }
],
"by_day": [
{ "date": "2026-05-14", "revenue": 412.50, "purchases": 5 }
]
}
conversion_rate_pct is sessions to purchase for that source: purchases from the source divided by sessions from the source, times 100. It is not leads to purchase. For that, divide this endpoint's totals.purchases by /v1/leads totals.leads.
GET /v1/leads
Lead counts with source attribution. This returns counts, not a list of people, so no personal data comes back from it.
Parameters: the common parameters only.
curl -H "Authorization: Bearer $TM_API_KEY" \
"https://app.truemetriks.com/v1/leads?site_id=42&period=last_30d"
{
"period": { "from": "2026-04-15", "to": "2026-05-15", "timezone": "UTC" },
"totals": { "leads": 287 },
"by_source": [
{ "source": "facebook", "channel": "Paid Social", "leads": 140 },
{ "source": "google", "channel": "Paid Search", "leads": 70 }
]
}
GET /v1/pages
Top pages by pageviews for the period. There is no source breakdown here by design.
Parameters (common parameters plus):
| Param | Description |
|---|---|
| limit | Rows to return, 1 to 100. Default 25 |
curl -H "Authorization: Bearer $TM_API_KEY" \
"https://app.truemetriks.com/v1/pages?site_id=42&period=last_7d&limit=5"
{
"period": { "from": "2026-05-08", "to": "2026-05-15", "timezone": "UTC" },
"pages": [
{ "path": "/", "pageviews": 5400, "unique_visitors": 3200, "avg_time_on_page_seconds": 32, "bounce_rate_pct": 41.2 }
]
}
GET /v1/products
Per-product revenue and units, plus the top product per source. Covers any Purchase event that shipped product details.
Parameters: the common parameters only.
curl -H "Authorization: Bearer $TM_API_KEY" \
"https://app.truemetriks.com/v1/products?site_id=42&period=last_30d"
{
"period": { "from": "2026-04-15", "to": "2026-05-15", "timezone": "UTC" },
"products": [
{ "sku": "TM-PRO-001", "product_name": "Premium Subscription", "units_sold": 100, "revenue": 11900.00, "average_price": 119.00 }
],
"by_source": [
{ "source": "facebook", "channel": "Paid Social", "top_product_sku": "TM-PRO-001", "top_product_name": "Premium Subscription", "revenue": 8700.00 }
]
}
GET /v1/users
Visitor counts and segmentation: new against returning, by source, and by country. These are aggregate counts, not a list of people.
Parameters: the common parameters only.
curl -H "Authorization: Bearer $TM_API_KEY" \
"https://app.truemetriks.com/v1/users?site_id=42&period=last_30d"
{
"period": { "from": "2026-04-15", "to": "2026-05-15", "timezone": "UTC" },
"totals": { "unique_visitors": 8200, "returning_visitors": 1100, "new_visitors": 7100 },
"by_source": [
{ "source": "facebook", "channel": "Paid Social", "visitors": 4100 }
],
"by_country": [
{ "country": "US", "visitors": 5200 },
{ "country": "DE", "visitors": 410 }
]
}
GET /v1/funnels
Your saved funnels with per-step visitor counts and conversion rates. If the site has no funnels defined, funnels comes back as an empty array.
Parameters: the common parameters only.
curl -H "Authorization: Bearer $TM_API_KEY" \
"https://app.truemetriks.com/v1/funnels?site_id=42&period=last_30d"
{
"period": { "from": "2026-04-15", "to": "2026-05-15", "timezone": "UTC" },
"funnels": [
{
"id": 1,
"name": "Checkout Funnel",
"steps": [
{ "step_name": "Product Page", "visitors": 1000, "conversion_from_previous_pct": 100 },
{ "step_name": "Add to Cart", "visitors": 350, "conversion_from_previous_pct": 35.0 },
{ "step_name": "Purchase", "visitors": 50, "conversion_from_previous_pct": 14.29 }
],
"overall_conversion_pct": 5.0
}
]
}
conversion_from_previous_pct compares each step with the step before it, while overall_conversion_pct compares the last step with the first.
Errors
Every error returns a JSON body with an error message and a machine-readable code.
| Status | Code | Meaning |
|---|---|---|
| 401 | AUTH_REQUIRED | No Authorization: Bearer header |
| 401 | INVALID_API_KEY | Key not found, expired, or revoked |
| 403 | TIER_NO_API_ACCESS | The workspace's plan does not include API access |
| 403 | SITE_ACCESS_DENIED | Key valid but the caller has no access to site_id |
| 400 | MISSING_SITE_ID | site_id was not supplied |
| 400 | BAD_SITE_ID | site_id is not a positive whole number |
| 400 | BAD_DATE_FORMAT | Dates are not YYYY-MM-DD, or only one of from/to was sent |
| 400 | INVERTED_RANGE | from is later than to |
| 400 | RANGE_TOO_WIDE | The range is longer than 366 days |
| 400 | BAD_PERIOD | period is not one of the six accepted values |
| 400 | BAD_TIMEZONE | timezone is not a valid IANA name |
| 429 | RATE_LIMITED | Per-key rate limit hit |
| 504 | QUERY_TIMEOUT | The query took longer than 10 seconds. Narrow the date range |
| 500 | INTERNAL | Something failed on our side |
Rate limits
Keys created on the Unlimited plan allow 200 requests per minute, measured over a rolling 60 second window. Going over returns 429 RATE_LIMITED; wait for the window to roll and retry.
The 60 second cache in front of every endpoint means a script that polls the same query repeatedly costs you far less than it looks: repeated identical requests inside that window come back from cache.
Building something bigger
The prompt at the top of this page suits an ordinary AI chat. For an agentic coding tool that can create files and run commands, like Claude Code or Codex, copy the whole page instead.
Open it in an empty folder, paste, and say what you want (for example, "fetch my revenue for last month and save it to a CSV"). Everything it needs is here.
Then paste it into Claude Code or Codex and tell it what data you want.
llms.txt
For LLM crawlers and code-completion tools, we publish a flat, summary-only index of this docs site at:
https://docs.truemetriks.com/llms.txt
It lists one line per docs page (title, URL, one-sentence description), grouped by section. It excludes long-form page bodies, the blog, and any anonymized customer data. A companion file, llms-full.txt, carries the full text of every page. Both regenerate on every docs deploy, and are byte-identical to the previous deploy when nothing changed.
That file describes the documentation. For the API itself there is a separate machine-readable manifest, served by the app rather than the docs site, which an AI can fetch directly:
https://app.truemetriks.com/api-docs/llms.txt
https://app.truemetriks.com/api-docs/openapi.json
The OpenAPI file is what you point a ChatGPT Custom GPT at when you want it to call the API as an Action.
Frequently asked questions
Is the API read-only?
Yes. The API is read-only: you use it to fetch your own analytics data, never to send data in. All endpoints are GET.
Where do I create an API key?
On the site's own Integrations tab, not in Account Settings. Open Settings for your site, click the Integrations tab, then click the API Keys tile and create a key there. The key is shown once, so copy it straight away.
Which plan do I need for API access?
The Unlimited plan. On Starter and Growth the API Keys tile is greyed out with an UNLIMITED padlock, and any request to a v1 endpoint is refused with 403 TIER_NO_API_ACCESS.
What are the rate limits?
200 requests per minute per key on the Unlimited plan, measured over a rolling 60 second window. Going over returns 429 RATE_LIMITED.
Why do I need to send start_date and end_date?
You do not. The v1 API uses period, or from and to, for its date range. There are no start_date or end_date parameters, and sending them is simply ignored, which silently gives you the default last 30 days.