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

# Account API

> Read your account, its plan, its current usage, and who is on the team.

## Base URL and authentication

```
https://api.traceten.com/v1
```

Every endpoint on this page takes `Authorization: Bearer <YOUR_API_KEY>` and needs the `stats:read` permission. Create a key under **Settings → API keys** ([details](/api/authentication)).

These are all reads. Changing your plan, your payment method, or your team is dashboard-only.

Listing [API keys](/api/api-keys) and [bot tokens](/api/bot-tokens) is different: with an API key those need `config:write`, because a credential inventory is not a metric. An AI app [connected to your account](/mcp/install) cannot use either listing at all.

## `GET /v1/account`

Who you are and what your plan allows.

```bash theme={null}
curl https://api.traceten.com/v1/account \
  -H "Authorization: Bearer <YOUR_API_KEY>"
```

```json theme={null}
{
  "id": "8f14e45f-ceea-467a-9f52-6c2b4dd8a1b3",
  "name": "Acme Inc",
  "region": "us",
  "created_at": "2026-01-14T10:02:11.000Z",
  "plan": "growth",
  "plan_name": "Growth",
  "event_limit": 350000,
  "crawl_limit": 650000,
  "site_limit": 3,
  "sites_used": 2,
  "visibility_prompt_limit": 8,
  "visibility_prompts_used": 6,
  "visibility_engines": ["perplexity_sonar", "google_ai_overviews"],
  "visibility_cadence": "ten_day",
  "billing_period_end": "2026-09-10T00:00:00.000Z",
  "overage_enabled": true,
  "crawl_overage_enabled": false,
  "payment_past_due": false,
  "pending_plan": null,
  "pending_plan_effective_at": null,
  "deletion_requested_at": null,
  "deletion_effective_at": null
}
```

| Field                     | Type             | Notes                                                                                                                         |
| ------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `id`                      | string           | Your account's internal id. Stable, and useful only for correlating your own logs.                                            |
| `name`                    | string \| null   | Display name. `null` if never set.                                                                                            |
| `region`                  | `"us"` \| `"eu"` | Where your data is stored.                                                                                                    |
| `plan`                    | string           | `starter`, `growth` or `scale`.                                                                                               |
| `event_limit`             | integer          | Billable events included per period. `0` means unlimited.                                                                     |
| `crawl_limit`             | integer          | AI-crawl hits included per period. `0` means unlimited.                                                                       |
| `site_limit`              | integer          | Sites your plan allows.                                                                                                       |
| `sites_used`              | integer          | Live sites. A site inside its 30-day deletion window does not count.                                                          |
| `visibility_prompt_limit` | integer          | AI-visibility prompts your plan allows, across your whole account. Never `0`.                                                 |
| `visibility_prompts_used` | integer          | Live prompts across all your sites. Active and paused count; archived does not.                                               |
| `visibility_engines`      | array            | The answer engines your prompts run on.                                                                                       |
| `visibility_cadence`      | string           | `ten_day` or `weekly`. How often each prompt is re-asked.                                                                     |
| `billing_period_end`      | string           | When the current period resets: the end of your Stripe billing period, or of the calendar month if you have never subscribed. |
| `overage_enabled`         | boolean          | Whether events past `event_limit` are billed rather than refused.                                                             |
| `crawl_overage_enabled`   | boolean          | Whether crawl hits past `crawl_limit` are billed.                                                                             |
| `payment_past_due`        | boolean          | A payment has failed.                                                                                                         |
| `pending_plan`            | string \| null   | A scheduled plan change, if any.                                                                                              |
| `deletion_requested_at`   | string \| null   | Non-null means the whole account is scheduled for deletion.                                                                   |

<Warning>
  `event_limit` and `crawl_limit` look alike and do not mean the same thing. `event_limit` is a
  **cap**: past it, we refuse to collect unless `overage_enabled` is true. What `crawl_limit` does
  past the allowance depends on your plan, so read `crawl_allowance_state` from [`GET
      /v1/account/usage`](#get-v1-account-usage) rather than comparing the two numbers yourself.
</Warning>

<Warning>
  `visibility_prompt_limit` counts differently from `site_limit`. Your sites share one prompt
  allowance, so `visibility_prompt_limit` is the total across your whole account, not a per-site
  figure. Do not multiply it by `sites_used`. It also never uses `0` to mean unlimited, because
  every prompt is a real query we send to an answer engine on your behalf.
</Warning>

This endpoint does not return your email address, your Clerk user id, or your Stripe ids. It identifies an account, not a person.

## `GET /v1/account/usage`

What you have consumed in the current billing period. This is the endpoint to poll if you want to catch an overage before the invoice does.

```bash theme={null}
curl https://api.traceten.com/v1/account/usage \
  -H "Authorization: Bearer <YOUR_API_KEY>"
```

```json theme={null}
{
  "plan": "growth",
  "events_used": 128442,
  "event_limit": 350000,
  "crawl_hits_used": 41207,
  "crawl_limit": 650000,
  "crawl_allowance_state": "under",
  "billing_period_end": "2026-09-10T00:00:00.000Z",
  "visibility_prompt_limit": 8,
  "visibility_prompts_used": 6,
  "visibility_engines": ["perplexity_sonar", "google_ai_overviews"],
  "visibility_cadence": "ten_day",
  "visibility_runs_used": 219,
  "visibility_scan_state": "active"
}
```

`events_used` is the unified figure: visitor events plus custom `traceten.track()` and conversion events. It resets at `billing_period_end`.

The limits here are the same values `GET /v1/account` reports, read from the same place, so the two cannot disagree.

`event_limit` and `crawl_limit` use `0` for unlimited. Check for zero before dividing:

```js theme={null}
const pct = usage.event_limit === 0 ? null : (usage.events_used / usage.event_limit) * 100;
```

### The AI-crawl allowance

`crawl_allowance_state` tells you what your crawl allowance is doing right now. We calculate it from your usage, your plan and your overage setting, so you do not have to.

| Value      | What it means                                                                                                                                                                                                                             |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `under`    | You are within your included allowance.                                                                                                                                                                                                   |
| `degraded` | You are past it on a plan that offers crawl overage, but overage is off. Your totals stay exact. We skip the reverse-DNS verification pass and stop keeping individual crawl records, so per-crawl detail is missing. Nothing is charged. |
| `metered`  | You are past it with crawl overage on. Full detail is kept and the extra hits are billed.                                                                                                                                                 |
| `capped`   | You are past it on a plan that does not offer crawl overage. New crawl hits are no longer recorded.                                                                                                                                       |

Only `capped` means your numbers have stopped moving. In that state `crawl_hits_used` is the real total we captured up to the limit, and it stays where it is until your next billing period starts or you upgrade. Everything recorded before the limit stays available.

Alert on the state, not on the arithmetic:

```js theme={null}
if (usage.crawl_allowance_state === "capped") {
  // Collection has stopped. Upgrade to resume it.
} else if (usage.crawl_allowance_state === "degraded") {
  // Totals are still exact, but per-crawl detail is missing.
}
```

### AI visibility

| Field                     | Type    | Notes                                                                           |
| ------------------------- | ------- | ------------------------------------------------------------------------------- |
| `visibility_prompt_limit` | integer | Prompts your plan allows, across your whole account. Never `0`.                 |
| `visibility_prompts_used` | integer | Live prompts across all your sites. Active and paused count; archived does not. |
| `visibility_engines`      | array   | The answer engines your prompts run on.                                         |
| `visibility_cadence`      | string  | `ten_day` or `weekly`. How often each prompt is re-asked.                       |
| `visibility_runs_used`    | integer | Engine runs so far this period.                                                 |
| `visibility_scan_state`   | string  | `active`, `paused_allowance` or `not_started`.                                  |

<Warning>
  Your AI-visibility allowance is per account, across every site. All of your sites draw on one
  `visibility_prompt_limit`, so you can have room on the site you are looking at and still be at
  your account limit. Every other number on this page is a billing total for the account too, but
  this is the one where per-site intuition gives the wrong answer.
</Warning>

`visibility_runs_used` counts engine runs, not prompts. One run is one prompt, asked on one engine, once. Because each prompt is asked several times on each engine every cycle, this number is much larger than `visibility_prompts_used`. The two are not comparable.

`visibility_scan_state` tells you whether new scans are being issued:

* `active`: scans are running.
* `not_started`: nothing has run yet this period.
* `paused_allowance`: you have used the period's scanning allowance, so we are not issuing new scans until it resets.

<Note>
  `paused_allowance` is not data loss. Every visibility figure we have already measured stays
  available and keeps being served in full. The only thing that stops is new measurement. Your
  scores, citations and competitor data are all still there, and scanning resumes at
  `billing_period_end`. You should not normally see this state: the allowance is sized above what a
  fully used plan needs, so reaching it usually means something went wrong on our side rather than
  on yours. If you see it, tell us and we will look.
</Note>

## `GET /v1/team`

The people who can act on your account, and what each of them can reach.

```bash theme={null}
curl https://api.traceten.com/v1/team \
  -H "Authorization: Bearer <YOUR_API_KEY>"
```

```json theme={null}
{
  "members": [
    {
      "user_id": "user_2nQ8xKpL0aBcDeFgHiJk",
      "membership_id": "orgmem_2nQ8xKpL0aBcDeFgHiJk",
      "role": "org:admin",
      "site_keys": null,
      "account_wide_admin": true
    },
    {
      "user_id": "user_2pR9yLqM1bCdEfGhIjKl",
      "membership_id": "orgmem_2pR9yLqM1bCdEfGhIjKl",
      "role": "org:admin",
      "site_keys": ["ttid_7Rb4TrC1dTbnD8w3s1TS12"],
      "account_wide_admin": false
    }
  ],
  "seats_used": 2,
  "seat_limit": 5
}
```

| Field                | Type                            | Notes                                                                                            |
| -------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------ |
| `user_id`            | string \| null                  | The member's id in your identity provider. `null` in the rare case it was omitted.               |
| `role`               | `"org:admin"` \| `"org:member"` | Their organisation role.                                                                         |
| `site_keys`          | array \| null                   | Snippet keys they are restricted to, narrowed to the sites you can see. Three states; see below. |
| `account_wide_admin` | boolean                         | `role` is admin **and** there is no site restriction.                                            |
| `seat_limit`         | integer \| null                 | Seats your plan allows. `null` if we could not read it.                                          |

<Note>
  Read `account_wide_admin`, not `role`. An `org:admin` restricted to specific sites is not an
  account-wide admin, and every permission gate in Traceten requires both halves. Someone with
  `role: "org:admin"` and a non-null `site_keys` cannot create sites, mint credentials, change your
  plan or delete the account.
</Note>

<Warning>
  `site_keys` has **three** states, not two. `null` means account-wide access. A non-empty array
  lists the sites that member is restricted to. An **empty array** means they are restricted, but
  only to sites your own credential cannot see: the list is narrowed to your scope, so an empty one
  is a gap in your view, never a member with no access. Read `account_wide_admin` to tell the two
  apart; it is computed from the member's full restriction, not from the narrowed list.
</Warning>

Members are identified by their id only. We do not return names or email addresses on this endpoint.

**Read-only.** Invites, removals and role changes happen in the dashboard under **Settings → Team**. There is no API path for them.

If we cannot read the member list, this returns `503` with `error: "clerk_unavailable"`. Retry. We do not return an empty team, because "this account has no members" would be a false statement to cache.

## Errors

| Status | `error`              | Cause                                       |
| ------ | -------------------- | ------------------------------------------- |
| `401`  | `unauthorized`       | Missing, malformed, revoked or expired key. |
| `403`  | `insufficient_scope` | The key is valid but lacks `stats:read`.    |
| `404`  | `account_not_found`  | No account backs this credential.           |
| `429`  | `rate_limited`       | Slow down. See the `retry-after` header.    |
| `503`  | `clerk_unavailable`  | `GET /v1/team` only. Retry.                 |

## Next

* [API keys](/api/api-keys) to mint and revoke credentials
* [Sites](/api/sites) to create and manage properties
* [Billing](/dashboard/billing) for plan changes, which stay in the dashboard
