---
title: "Usage & billing"
description: "What counts against your quota, what's free, and how to track spend per API key."
---
You're billed for what supermemory processes, not what it stores. Tokens are counted once, at ingestion — searches, profile reads, and memory injection don't draw them down.
Start by checking where you stand:
```typescript TypeScript
const res = await fetch("https://api.supermemory.ai/v3/auth/billing/usage", {
headers: { Authorization: `Bearer ${process.env.SUPERMEMORY_API_KEY}` },
});
const { items, periodStart, periodEnd } = await res.json();
```
```python Python
import requests
res = requests.get(
"https://api.supermemory.ai/v3/auth/billing/usage",
headers={"Authorization": f"Bearer {SUPERMEMORY_API_KEY}"},
)
usage = res.json()
```
```bash cURL
curl "https://api.supermemory.ai/v3/auth/billing/usage" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY"
```
You get back each meter with its usage and limit, plus your current billing period:
```json
{
"items": [
{ "name": "sm tokens text", "used": 184203, "limit": 1000000, "unit": "tokens" },
{ "name": "sm search queries", "used": 4210, "limit": 100000, "unit": "queries" }
],
"periodStart": "2026-07-01T00:00:00.000Z",
"periodEnd": "2026-08-01T00:00:00.000Z"
}
```
{/* CONFIRM: billing usage response shape and exact meter names */}
One thing to know up front: scoped API keys can **not** read billing endpoints — they return a 403. Use an unscoped key, or check the billing page in the console instead. {/* CONFIRM: scoped-key 403 on billing endpoints */}
## What "tokens processed" counts
Every document you add — via the API, a connector, MCP, or any other door — goes through the ingestion pipeline. The tokens of the **extracted content** are what's metered. Not your raw upload size, not the embeddings, not the memories derived from it: the token count of the text supermemory pulled out of your document.
Two meters exist:
- **Text tokens** — plain text, tweets, markdown.
- **Rich content tokens** — PDFs, images, files, web pages. Anything that needs extraction before it's text.
Rich content costs more per token than plain text, because extraction does more work. {/* CONFIRM: text vs rich meter split and relative pricing */} If you can send markdown instead of a PDF of the same content, send markdown — it's also what the [ingestion guide](/patterns/ingestion) recommends for quality reasons.
Updates are billed on the **delta**. When you update a document (or re-add one with the same `customId`), you're charged only for the token count *increase* over what that document already cost. Re-processing unchanged content bills zero. So appending a session to an existing conversation document charges you for the new turns, not the whole history again — this is why [ingesting full conversations under one `customId`](/patterns/ingestion) is cheaper than adding every turn as its own document. {/* CONFIRM: delta billing on updates and customId re-adds */}
And the reads are not on this meter at all:
- **Search** is metered per query, not per token — and priced low enough that it's effectively free at any realistic volume. Ingestion is where your money goes.
- **Profile reads** don't consume tokens. A `client.profile({ containerTag })` call isn't metered; add a `q` and it counts as one search query.
- **Memory injection** — the AI SDK wrapper putting a profile or search results into your prompt — is a profile/search read under the hood, so it follows the same rules. It never consumes ingestion tokens. {/* CONFIRM: injection billing — verified in code (read paths only hit the search-query meter), confirm this is the publishable statement */}
- **Storage is free.** A document you ingested in January costs nothing to keep in July.
## Deleting documents does not restore quota
The meter counts processing, and the processing already happened. Deleting a document removes its content, chunks, and derived memories — but the tokens it consumed stay consumed. Your quota is a record of work done, not a measure of what's currently stored.
Your quota refreshes at the start of each billing period. Unused quota doesn't roll over. {/* CONFIRM: monthly refresh cadence + no-rollover on all plans */}
If you're near the limit, deleting old documents won't buy you headroom — upgrading or waiting for the reset will.
## Model your costs
The mental math is short:
1. **Ingestion is the cost driver.** Estimate the tokens in what you'll send — that's most of your bill.
2. **Search is ~free.** Query as much as you want; per-query pricing is negligible next to ingestion.
3. **Profiles are cheap to use.** A profile fits in roughly a 1k-token budget and its shape is stable between updates, so it's prompt-cache-friendly on the LLM side too.
4. **Send conversations, not turns.** One document per session with a `customId` beats one document per message — better memories *and* delta billing.
## Cut costs with `taskType: "superrag"`
If a set of documents only needs to be searchable — you'll never want derived memories, a graph, or profile contributions from it — ingest it with `taskType: "superrag"`. That runs the retrieval-only pipeline (extract, chunk, embed) and skips memory derivation, at about 5x cheaper per token than the default `"memory"` task type. {/* CONFIRM: taskType param name and "superrag"/"memory" values */}
A support-docs corpus is the typical case:
```typescript TypeScript
const res = await fetch("https://api.supermemory.ai/v3/documents", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SUPERMEMORY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
content: "https://help.acme.dev/articles/refund-policy",
containerTag: "acme_help_center",
taskType: "superrag",
}),
});
```
```python Python
import requests
requests.post(
"https://api.supermemory.ai/v3/documents",
headers={"Authorization": f"Bearer {SUPERMEMORY_API_KEY}"},
json={
"content": "https://help.acme.dev/articles/refund-policy",
"containerTag": "acme_help_center",
"taskType": "superrag",
},
)
```
```bash cURL
curl -X POST "https://api.supermemory.ai/v3/documents" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "https://help.acme.dev/articles/refund-policy",
"containerTag": "acme_help_center",
"taskType": "superrag"
}'
```
Use `"memory"` (the default) for anything about your users — conversations, preferences, facts you want the engine to reason over. Use `"superrag"` for reference material you only retrieve. The examples above use raw `POST /v3/documents` because the TS SDK typings don't include `taskType` yet.
Documents ingested with `"superrag"` show up in [document search](/search) but don't produce memories, so they won't appear in memory search results or [profiles](/concepts/user-profiles).
## Track usage per API key
If you run one key per environment — or per tenant — you can see exactly which key spent what. `GET /v3/analytics/usage` breaks usage down by key, including tokens:
```typescript TypeScript
const res = await fetch(
"https://api.supermemory.ai/v3/analytics/usage?period=30d",
{ headers: { Authorization: `Bearer ${process.env.SUPERMEMORY_API_KEY}` } },
);
const { byKey } = await res.json();
```
```python Python
import requests
res = requests.get(
"https://api.supermemory.ai/v3/analytics/usage",
params={"period": "30d"},
headers={"Authorization": f"Bearer {SUPERMEMORY_API_KEY}"},
)
by_key = res.json()["byKey"]
```
```bash cURL
curl "https://api.supermemory.ai/v3/analytics/usage?period=30d" \
-H "Authorization: Bearer $SUPERMEMORY_API_KEY"
```
Each entry in `byKey` carries the token total for that key:
```json
{
"byKey": [
{
"keyId": "key_prod_4f8a",
"keyName": "Production API",
"count": 23410,
"tokensUsed": 1284203,
"avgDuration": 98.7,
"lastUsed": "2026-07-15T14:35:00Z"
}
],
"usage": [
{ "type": "add", "count": 1523, "avgDuration": 245.5 },
{ "type": "search", "count": 3421, "avgDuration": 89.2 }
]
}
```
The endpoint also accepts `from`/`to` (ISO 8601) instead of `period`, and paginates with `page` and `limit`. {/* CONFIRM: analytics usage response fields and query params */} The same family has `/v3/analytics/errors` and `/v3/analytics/logs` for error breakdowns and request-level logs.
## Handle running out
When a meter is exhausted, writes start returning `402` with a body that names the meter:
```json
{
"error": "Text tokens limit reached",
"details": "You've run out of credits. Top up to continue."
}
```
{/* CONFIRM: 402 status and exact body shape */}
Catch the `402` in your ingestion path and queue the writes — reads keep working, so your app degrades to "remembers everything up to now" rather than breaking. Whether usage past the included quota bills as overage or hard-blocks depends on your plan and its overage setting. {/* CONFIRM: overage defaults and availability by plan */}
## Manage invoices, downgrades, and cancellation
Invoices, payment methods, plan changes, and cancellation all live in the console's billing settings. {/* CONFIRM: exact console navigation path */} Only org admins can manage billing.
When you downgrade or cancel, your data is not deleted — you keep read access, and ingestion is governed by the lower plan's quota from the next billing period. {/* CONFIRM: plan-downgrade data behavior — verify data retention and any limits enforcement on existing over-quota data */}
That's the whole meter: pay when supermemory processes, read for ~free, and delete for hygiene — not refunds.
## Where next
- [Ingestion best practices](/patterns/ingestion) — the patterns that make ingestion cheaper *and* produce better memories
- [Errors and limits](/errors-and-limits) — rate limits, the 429 shape, and backoff
- [User profiles](/concepts/user-profiles) — what that ~1k-token budget buys you
- [Security](/trust/security) — scoped keys, deletion mechanics, and compliance