Billing and usage
Subscriptions, pay-as-you-go credits, spend caps, and usage reporting on the CognitiveX API.
The billing surface lives under /api/billing/* on https://api.cognitivx.io.
It covers four things: subscriptions (Stripe Checkout and the customer portal),
pay-as-you-go (PAYG) credits and top-ups, spend caps, and usage reporting.
All endpoints below require authentication unless noted. Pass either header:
Authorization: Bearer icog_xxx
X-API-Key: icog_xxxCreate keys at developers.cognitivx.io/keys. See Authentication for the full picture.
Money is denominated in US dollars on this surface, either as float USD
fields (for example amount_usd, monthly_cap_usd) or as integer credits
on the PAYG balance. The conversion is fixed: 1 credit = $0.0001, so
10,000 credits = $1.00. Top-ups are whole dollars. There is no amount_cents
field anywhere in the billing surface.
Tiers
Four tiers exist. amnesiac is the free default; awakened and conscious
are paid subscriptions; payg is metered pay-as-you-go.
| Tier | Display name | Monthly | Annual | Recall credits / month | Memory cap |
|---|---|---|---|---|---|
amnesiac | Free | $0 | — | 100 | 1,000 |
awakened | Awakened | $20 | $199 | 500,000 | 1,000,000 |
conscious | Conscious | $200 | $1,999 | 15,000,000 | unlimited |
payg | Pay-as-You-Go | $0 | — | unlimited (spend-metered) | unlimited |
The live catalog is served by GET /api/billing/tiers (below); treat these
numbers as illustrative and read the endpoint for the current values.
Subscriptions
Get billing status
One-line: read the caller's current tier, subscription state, and PAYG summary.
GET /api/billing/me
Auth required.
No request body. Returns the user's tier, Stripe-derived subscription status, trial and renewal dates, the live billing interval, and a PAYG snapshot so a client can decide whether to render a "Switch to PAYG" CTA without a second call.
curl https://api.cognitivx.io/api/billing/me \
-H "Authorization: Bearer icog_xxx"{
"tier": "awakened",
"subscription_status": "active",
"trial_ends_at": null,
"renewal_date": "2026-07-16",
"subscription_interval": "monthly",
"payg_eligible": true,
"payg_balance_usd": 0.0,
"payg_transactions_30d": 0
}subscription_interval is "monthly", "annual", or null (for amnesiac
and payg, which have no subscription). payg_balance_usd is null when the
user has never held a credit balance.
Get the tier catalog
One-line: fetch the tier configuration for a pricing page.
GET /api/billing/tiers
No auth required (public).
curl https://api.cognitivx.io/api/billing/tiersReturns the tier configuration object (display names, monthly and annual prices, per-month recall-credit caps, and memory caps per tier).
Start a subscription checkout
One-line: create a Stripe Checkout session and redirect the user to pay.
POST /api/billing/create-checkout
Auth required.
| Field | Type | Required | Description |
|---|---|---|---|
tier | string | yes | awakened or conscious. Any other value is rejected. |
interval | string | no | monthly (default) or annual. |
The response url is a Stripe-hosted Checkout page. Redirect the browser
there; on success Stripe sends the user back to your app and a webhook
activates the subscription. If the webhook lags, call
/verify-checkout to close the gap.
curl -X POST https://api.cognitivx.io/api/billing/create-checkout \
-H "Authorization: Bearer icog_xxx" \
-H "Content-Type: application/json" \
-d '{"tier": "awakened", "interval": "monthly"}'import { configureApiClient, billing } from '@cognitivx/sdk';
configureApiClient({ apiKey: process.env.ICOG_API_KEY });
const { url } = await billing.createCheckout({
tier: 'awakened',
interval: 'monthly',
});
// redirect the browser to `url`{ "url": "https://checkout.stripe.com/c/pay/cs_test_a1B2c3..." }Errors
| Status | When |
|---|---|
| 400 | tier is not awakened or conscious, or no Stripe price is configured for the tier and interval. |
| 500 | Stripe customer or checkout-session creation failed. |
Verify a checkout
One-line: poll Stripe to confirm a just-completed checkout activated the plan.
POST /api/billing/verify-checkout
Auth required.
| Field | Type | Required | Description |
|---|---|---|---|
session_id | string | yes | The Checkout session id from the success redirect. |
Call this from your success page (the redirect URL includes the session id).
It checks Stripe's payment_status and, when paid, flips the user to the
purchased tier. Idempotent with the webhook; returns activated: false if the
session is not yet paid.
curl -X POST https://api.cognitivx.io/api/billing/verify-checkout \
-H "Authorization: Bearer icog_xxx" \
-H "Content-Type: application/json" \
-d '{"session_id": "cs_test_a1B2c3..."}'{ "activated": true }Errors
| Status | When |
|---|---|
| 400 | The user has no Stripe customer, or the session belongs to a different customer. |
| 500 | Stripe session retrieval failed. |
Switch monthly and annual
One-line: change an active subscription's billing interval mid-cycle.
POST /api/billing/change-interval
Auth required.
| Field | Type | Required | Description |
|---|---|---|---|
interval | string | yes | monthly or annual. |
Stripe applies a proration: the unused portion of the current interval is credited against the new interval's invoice. There is no cash refund; the credit (or debit) shows up on the next invoice. If the user is already on the requested interval, the call is a no-op.
curl -X POST https://api.cognitivx.io/api/billing/change-interval \
-H "Authorization: Bearer icog_xxx" \
-H "Content-Type: application/json" \
-d '{"interval": "annual"}'import { configureApiClient, billing } from '@cognitivx/sdk';
const res = await billing.changeInterval({ interval: 'annual' });
// res.status is "switched" or "noop"{
"status": "switched",
"message": "Switched to annual. Stripe proration applied; see next invoice.",
"subscription_id": "sub_1Nxyz...",
"new_price_id": "price_annual_awakened",
"previous_price_id": "price_monthly_awakened"
}When already on the target interval, status is "noop" and previous_price_id
is omitted.
Errors
| Status | When |
|---|---|
| 400 | The user's tier is not a paid subscription (awakened/conscious), or no price is configured for the tier and interval. |
| 404 | The Stripe subscription could not be found. |
| 409 | The user has no active subscription. Use create-checkout for new subscriptions. |
| 502 | Stripe rejected the modification. |
Open the billing portal
One-line: create a Stripe customer-portal session for self-service management.
POST /api/billing/create-portal
Auth required.
No request body. The portal is where customers update cards, view invoices, and
cancel. Redirect the browser to the returned url.
curl -X POST https://api.cognitivx.io/api/billing/create-portal \
-H "Authorization: Bearer icog_xxx"import { configureApiClient, billing } from '@cognitivx/sdk';
const { url } = await billing.createPortal();
// redirect the browser to `url`{ "url": "https://billing.stripe.com/p/session/test_a1B2c3..." }Errors
| Status | When |
|---|---|
| 400 | The user has no Stripe customer (no subscription has ever been started). |
| 500 | Stripe portal-session creation failed. |
Invoices are not served by the CognitiveX API. They live in Stripe; send
users to the portal (/create-portal) to view and download them. For a
machine-readable PAYG spend export, use
/payg-receipts.csv.
Pay-as-you-go (PAYG)
PAYG bills metered spend against a prepaid credit balance instead of a flat monthly subscription. Spend is OpenRouter cost times a fixed markup. Users top up a dollar balance, spend it down, and can cap their monthly spend.
Switch to PAYG
One-line: cancel any active subscription and move the user to metered billing.
POST /api/billing/switch-to-payg
Auth required.
| Field | Type | Required | Description |
|---|---|---|---|
refund_method | string | no | credit (default) leaves the proration on the Stripe customer balance, applied to the next charge. card issues a refund on the most recent subscription charge back to the original payment method. |
Behavior depends on the current tier. amnesiac just flips the tier (no
subscription to cancel). awakened/conscious cancels the active subscription
immediately with proration. payg is idempotent and returns already_payg: true.
curl -X POST https://api.cognitivx.io/api/billing/switch-to-payg \
-H "Authorization: Bearer icog_xxx" \
-H "Content-Type: application/json" \
-d '{"refund_method": "credit"}'{
"already_payg": false,
"refunded_usd": 12.33,
"refund_method": "credit",
"new_tier": "payg",
"requires_topup": true
}requires_topup is true when the credit balance is <= 0 after switching, so
the client knows to prompt for a top-up before the user can spend.
Errors
| Status | When |
|---|---|
| 404 | User not found. |
| 502 | Stripe could not be reached to list or cancel the subscription. |
Top up credits
One-line: create a Stripe PaymentIntent to add credit to the PAYG balance.
POST /api/billing/topup
Auth required.
| Field | Type | Required | Description |
|---|---|---|---|
amount_usd | integer | yes | Whole dollars to add. Minimum $5, maximum $500. |
intent_to_switch | boolean | no | Default false. Set true when this top-up is part of an "amnesiac switches to PAYG" flow; the Stripe webhook then auto-promotes the user on payment. |
Returns a Stripe client_secret and the PaymentIntent id. Confirm the payment
client-side with Stripe.js; the credit lands on the balance once the payment
succeeds (handled by webhook). amount_usd is converted to credits at
10,000 credits per dollar.
curl -X POST https://api.cognitivx.io/api/billing/topup \
-H "Authorization: Bearer icog_xxx" \
-H "Content-Type: application/json" \
-d '{"amount_usd": 25}'import { configureApiClient, billing } from '@cognitivx/sdk';
const { client_secret } = await billing.topup({ amount_usd: 25 });
// confirm `client_secret` with Stripe.js{
"client_secret": "pi_3Nxyz..._secret_abc",
"payment_intent_id": "pi_3Nxyz..."
}Errors
| Status | When |
|---|---|
| 422 | amount_usd is below $5 or above $500. Body is {"error": "invalid_amount", "message": "..."}. |
Get the credit balance
One-line: read the current PAYG credit balance and low-balance flags.
GET /api/billing/balance
Auth required.
curl https://api.cognitivx.io/api/billing/balance \
-H "Authorization: Bearer icog_xxx"{
"balance_credits": 245000,
"balance_usd": 24.5,
"low_balance": false,
"depleted": false
}| Field | Type | Description |
|---|---|---|
balance_credits | integer | Canonical credit balance. 1 credit = $0.0001. |
balance_usd | number | Back-compat alias, balance_credits * 0.0001. |
low_balance | boolean | true when below 20,000 credits ($2.00). |
depleted | boolean | true once the balance has been fully spent. |
A user who has never held credit gets all-zero, non-depleted defaults.
Estimate PAYG cost
One-line: project what the last 30 days of usage would cost on PAYG.
GET /api/billing/payg-estimate
Auth required.
No request body. Pulls the user's raw spend over the trailing 30 days, applies the PAYG markup, and contrasts it with their current tier's effective price for a comparison UI.
curl https://api.cognitivx.io/api/billing/payg-estimate \
-H "Authorization: Bearer icog_xxx"{
"raw_spend_30d_usd": 8.42,
"projected_payg_30d_usd": 10.95,
"current_tier": "awakened",
"current_tier_price_usd": 20.0,
"effective_current_price_usd": 20.0,
"savings_vs_current_usd": 9.05,
"markup_multiplier": 1.3,
"model_breakdown": [
{
"model": "gemini-2.5-flash",
"tokens_in": 412000,
"tokens_out": 88000,
"cost_raw_usd": 6.10,
"cost_payg_usd": 7.93
}
]
}effective_current_price_usd is what the user actually pays right now (0 on a
trial, free tier, or canceled subscription). savings_vs_current_usd is
positive when PAYG would be cheaper.
Set or clear a spend cap
One-line: cap monthly PAYG spend; requests hard-block once the cap is reached.
PUT /api/billing/payg-cap
Auth required.
| Field | Type | Required | Description |
|---|---|---|---|
monthly_cap_usd | number or null | yes | Dollar cap for the calendar month. Range $1 to $10,000. Pass null to remove the cap. |
The cap is enforced at request time: once cumulative billable spend in the current calendar month reaches it, further work is blocked until the next month or until the cap is raised or cleared.
curl -X PUT https://api.cognitivx.io/api/billing/payg-cap \
-H "Authorization: Bearer icog_xxx" \
-H "Content-Type: application/json" \
-d '{"monthly_cap_usd": 50}'import { configureApiClient, billing } from '@cognitivx/sdk';
await billing.setPaygCap({ monthly_cap_usd: 50 });
// clear with: billing.setPaygCap({ monthly_cap_usd: null }){
"monthly_cap_usd": 50.0,
"spent_this_month_usd": 12.4
}Errors
| Status | When |
|---|---|
| 422 | monthly_cap_usd is below $1 or above $10,000. Body is {"error": "invalid_cap", "message": "..."}. |
Get the spend cap
One-line: read the current monthly cap and month-to-date spend.
GET /api/billing/payg-cap
Auth required.
curl https://api.cognitivx.io/api/billing/payg-cap \
-H "Authorization: Bearer icog_xxx"{
"monthly_cap_usd": 50.0,
"spent_this_month_usd": 12.4
}monthly_cap_usd is null when no cap is set.
List PAYG transactions
One-line: read the recent PAYG ledger for a transaction list.
GET /api/billing/payg-transactions
Auth required.
| Param | In | Type | Required | Description |
|---|---|---|---|---|
limit | query | integer | no | Number of rows, default 30. Clamped to 1–100. |
curl "https://api.cognitivx.io/api/billing/payg-transactions?limit=10" \
-H "Authorization: Bearer icog_xxx"{
"transactions": [
{
"id": 4821,
"event_type": "spend",
"amount_usd": -0.0123,
"balance_after": 24.4877,
"model": "gemini-2.5-flash",
"created_at": "2026-06-16T14:02:11.481000+00:00"
},
{
"id": 4795,
"event_type": "topup",
"amount_usd": 25.0,
"balance_after": 24.5,
"model": null,
"created_at": "2026-06-15T09:10:00.000000+00:00"
}
]
}event_type is the ledger action (spend, topup, proration_credit, and
similar). Spend rows are negative amount_usd; model is null for non-spend
rows.
Export PAYG receipts
One-line: download a CSV of all PAYG ledger rows for a month.
GET /api/billing/payg-receipts.csv
Auth required.
| Param | In | Type | Required | Description |
|---|---|---|---|---|
month | query | string | no | YYYY-MM. Defaults to the current month. |
Returns text/csv with a Content-Disposition: attachment header so the
browser downloads a file. Columns: timestamp_utc, event_type, amount_usd,
balance_after_usd, model, stripe_id. Useful for reimbursement and
accounting.
curl "https://api.cognitivx.io/api/billing/payg-receipts.csv?month=2026-06" \
-H "Authorization: Bearer icog_xxx" -OJtimestamp_utc,event_type,amount_usd,balance_after_usd,model,stripe_id
2026-06-15T09:10:00+00:00,topup,25.000000,25.0000,,pi_3Nxyz...
2026-06-16T14:02:11.481000+00:00,spend,-0.012300,24.4877,gemini-2.5-flash,Errors
| Status | When |
|---|---|
| 422 | month is not in YYYY-MM format. |
Usage reporting
Current-month usage
One-line: read this month's usage counters and recall-credit breakdown.
GET /api/billing/usage
Auth required.
No request body. Returns the base counters (message, memory_write,
image_gen) plus recall-credit consumption for the current month, the tier cap,
and a few display helpers.
curl https://api.cognitivx.io/api/billing/usage \
-H "Authorization: Bearer icog_xxx"{
"message": 312,
"memory_write": 47,
"image_gen": 3,
"recall_credit_count": 18420,
"recall_credits_per_month": 500000,
"recall_credit_breakdown": {
"foundational": 1200,
"quick": 4100,
"standard": 9800,
"deep": 3000,
"identity": 320
},
"cap_reset_at": "2026-07-01T00:00:00Z",
"memories_saved_this_month": 47,
"show_onboarding_explainer": false
}| Field | Type | Description |
|---|---|---|
message, memory_write, image_gen | integer | Base usage counters for the month. |
recall_credit_count | integer | Total recall credits consumed this month. |
recall_credits_per_month | integer or null | The tier cap. null for PAYG (uncapped). |
recall_credit_breakdown | object | Per-mode credit sums; all five modes always present. |
cap_reset_at | string | ISO timestamp of the next monthly reset (first of next month, UTC). |
memories_saved_this_month | integer | Memory writes this month, positive framing. |
show_onboarding_explainer | boolean | One-shot flag, true once after the first paid signup, then cleared. |
Daily usage history
One-line: read daily usage buckets for billing charts.
GET /api/billing/usage-history
Auth required.
| Param | In | Type | Required | Description |
|---|---|---|---|---|
days | query | integer | no | Window length, default 30. Clamped to 1–90. |
Each day reports user messages, memory writes, generated images, and per-bucket counts of credit-consuming actions, plus total credits charged that day.
curl "https://api.cognitivx.io/api/billing/usage-history?days=7" \
-H "Authorization: Bearer icog_xxx"{
"days": 7,
"history": [
{
"date": "2026-06-16",
"messages": 42,
"memory_writes": 6,
"images": 1,
"recalls": 88,
"chats": 42,
"dreams": 1,
"insights": 0,
"lens_regens": 0,
"mcp_calls": 12,
"other_actions": 3,
"credits": 2640
}
]
}Memory capacity
One-line: read total stored-memory capacity for the user.
GET /api/billing/memory-capacity
Auth required.
curl https://api.cognitivx.io/api/billing/memory-capacity \
-H "Authorization: Bearer icog_xxx"Returns the user's total stored-memory count against their tier cap. The shape
follows the tier's memory_cap_total (see Tiers); conscious and
payg are uncapped.
My LLM cost breakdown
One-line: read the caller's own raw LLM cost for a month.
GET /api/costs/me
Auth required. Mounted under /api/costs, not /api/billing.
| Param | In | Type | Required | Description |
|---|---|---|---|---|
month | query | string | no | YYYY-MM. Defaults to the current month. |
Returns the raw OpenRouter cost breakdown for the user (this is underlying cost, not the marked-up PAYG price).
curl "https://api.cognitivx.io/api/costs/me?month=2026-06" \
-H "Authorization: Bearer icog_xxx"Errors
| Status | When |
|---|---|
| 503 | The cost tracker is not initialized on the server. |
Webhooks
Stripe webhook
POST /api/billing/webhooks/stripe
No bearer auth. Authenticated by Stripe signature.
This endpoint is for Stripe to call, not you. It verifies the
stripe-signature header against the configured webhook secret, records the
event idempotently, and processes it in the background (subscription activation,
top-up credit, cancellation reconciliation).
{ "received": true }Errors
| Status | When |
|---|---|
| 400 | The stripe-signature header is missing, the payload is invalid, or the signature does not verify. |
Do not call this endpoint yourself. It only accepts requests signed with the Stripe webhook secret. Configure it as the destination in your Stripe dashboard.
Admin endpoints
These require an admin token (require_admin). They are not part of the normal
developer surface and are listed for completeness.
| Method | Path | Purpose |
|---|---|---|
| GET | /api/costs/admin/users | Cost summary for all users, with emails, sorted by cost. |
| GET | /api/costs/admin/user/{user_id} | Detailed cost breakdown for one user. |
| GET | /api/costs/admin/by_task | Per-task, per-model aggregate cost (count, mean, stddev, latency, fallback rate). |
| POST | /api/costs/admin/set-tier/{user_id}/{tier} | Force a user's tier (amnesiac/awakened/conscious). Use me to change your own. |
| GET | /api/admin/analytics/costs | Monthly cost breakdown by model, user, and role, with budget status. |
| GET | /api/admin/analytics/costs/trends | Cost time series (daily/weekly/monthly) over N months. |
| GET | /api/admin/analytics/payg-overflow | PAYG-overflow cohort metrics for Conscious subscribers who buy top-ups. |
All admin cost endpoints accept an optional month (YYYY-MM) query param and
return 503 if the cost tracker is not initialized. set-tier returns 400 for an
invalid tier value.