CognitiveX Docs

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_xxx

Create 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.

TierDisplay nameMonthlyAnnualRecall credits / monthMemory cap
amnesiacFree$0—1001,000
awakenedAwakened$20$199500,0001,000,000
consciousConscious$200$1,99915,000,000unlimited
paygPay-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/tiers

Returns 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.

FieldTypeRequiredDescription
tierstringyesawakened or conscious. Any other value is rejected.
intervalstringnomonthly (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

StatusWhen
400tier is not awakened or conscious, or no Stripe price is configured for the tier and interval.
500Stripe 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.

FieldTypeRequiredDescription
session_idstringyesThe 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

StatusWhen
400The user has no Stripe customer, or the session belongs to a different customer.
500Stripe 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.

FieldTypeRequiredDescription
intervalstringyesmonthly 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

StatusWhen
400The user's tier is not a paid subscription (awakened/conscious), or no price is configured for the tier and interval.
404The Stripe subscription could not be found.
409The user has no active subscription. Use create-checkout for new subscriptions.
502Stripe 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

StatusWhen
400The user has no Stripe customer (no subscription has ever been started).
500Stripe 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.

FieldTypeRequiredDescription
refund_methodstringnocredit (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

StatusWhen
404User not found.
502Stripe 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.

FieldTypeRequiredDescription
amount_usdintegeryesWhole dollars to add. Minimum $5, maximum $500.
intent_to_switchbooleannoDefault 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

StatusWhen
422amount_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
}
FieldTypeDescription
balance_creditsintegerCanonical credit balance. 1 credit = $0.0001.
balance_usdnumberBack-compat alias, balance_credits * 0.0001.
low_balancebooleantrue when below 20,000 credits ($2.00).
depletedbooleantrue 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.

FieldTypeRequiredDescription
monthly_cap_usdnumber or nullyesDollar 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

StatusWhen
422monthly_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.

ParamInTypeRequiredDescription
limitqueryintegernoNumber 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.

ParamInTypeRequiredDescription
monthquerystringnoYYYY-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" -OJ
timestamp_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

StatusWhen
422month 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
}
FieldTypeDescription
message, memory_write, image_genintegerBase usage counters for the month.
recall_credit_countintegerTotal recall credits consumed this month.
recall_credits_per_monthinteger or nullThe tier cap. null for PAYG (uncapped).
recall_credit_breakdownobjectPer-mode credit sums; all five modes always present.
cap_reset_atstringISO timestamp of the next monthly reset (first of next month, UTC).
memories_saved_this_monthintegerMemory writes this month, positive framing.
show_onboarding_explainerbooleanOne-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.

ParamInTypeRequiredDescription
daysqueryintegernoWindow 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.

ParamInTypeRequiredDescription
monthquerystringnoYYYY-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

StatusWhen
503The 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

StatusWhen
400The 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.

MethodPathPurpose
GET/api/costs/admin/usersCost 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_taskPer-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/costsMonthly cost breakdown by model, user, and role, with budget status.
GET/api/admin/analytics/costs/trendsCost time series (daily/weekly/monthly) over N months.
GET/api/admin/analytics/payg-overflowPAYG-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.