Prefer Swagger UI? Click hereThe same API in the classic OpenAPI explorer.
POST/v1/customers

Customers

First-class end-user primitive. Tracks spend, enforces budgets, and scopes Client Tokens. Look up an existing customer by your own ID via GET /v1/customers?external_id=… (list filter) or GET /v1/customers/ext:<external_id> (direct fetch — also works on /wallet, /usage, /conversations, /client_tokens, /margin subroutes).

Request
HTTP
POST
URL
/v1/customers
Auth
api_key
Try it
# Create
curl https://api.fightclub.pro/v1/customers \
  -H "Authorization: Bearer $FC_API_KEY" \
  -d '{"external_id":"u_42","display_name":"Alice","monthly_budget_usd":50}'

# Look up by your external_id (two ways)
# 1. List filter — returns {data, has_more, next_cursor}
curl "https://api.fightclub.pro/v1/customers?external_id=u_42" \
  -H "Authorization: Bearer $FC_API_KEY"

# 2. Direct fetch with ext: prefix — single object, also works on subroutes
curl https://api.fightclub.pro/v1/customers/ext:u_42 \
  -H "Authorization: Bearer $FC_API_KEY"
curl https://api.fightclub.pro/v1/customers/ext:u_42/wallet \
  -H "Authorization: Bearer $FC_API_KEY"

Example response

{
  "id": "cus_42",
  "external_id": "tenant_42",
  "display_name": "Acme Corp",
  "status": "active",
  "monthly_budget_usd": 50.0,
  "rpm_limit": null,
  "tpm_limit": null,
  "default_billable_markup_pct": 20.0,
  "default_billable_amount_usd": null,
  "wallet_balance_usd": null,
  "lifetime_spend_usd": 3.71,
  "created_at": "2026-06-24T12:00:00.000Z"
}

A representative 200 body. Ids and timestamps are illustrative.

Body parameters

NameTypeDefaultDescription
external_idstringoptionalYour own id for this customer (your tenant or user id). Lets you address them later by ext:<external_id> on any customer route. Unique within your account.
display_namestringoptionalHuman-readable name shown in the dashboard.
monthly_budget_usdnumberoptionalMonthly spend ceiling in USD (>= 0). When attributed spend would exceed it, calls for this customer return 402 customer_budget_exceeded — your wallet still has money.
rpm_limitintegeroptionalPer-customer requests-per-minute cap (positive integer).
tpm_limitintegeroptionalPer-customer tokens-per-minute cap (positive integer).
default_billable_markup_pctnumberoptionalMarkup added to raw cost to compute what this customer is billed (e.g. 20 = +20%). >= 0. Mutually exclusive with default_billable_amount_usd.
default_billable_amount_usdnumberoptionalA flat billable amount per call instead of a markup. >= 0. Mutually exclusive with default_billable_markup_pct.
metadataobjectoptionalFree-form JSON, up to 4 KB serialized.

* required.

Query parameters

NameTypeDefaultDescription
limitinteger20Page size for GET /v1/customers.
afterstringoptionalCursor: the id of the last row from the previous page.
statusstringoptionalFilter by status: active | archived.
external_idstringoptionalFilter to the customer with this external_id (returns a single-item list).
order_bystringcreated_desccreated_asc | created_desc | last_active_desc.

Headers

HeaderDirDescription
FC-Customerreq →On any metered call (chat, embeddings, runs, file_search…): attribute that call's cost + usage to this customer id.
X-Ringside-Wallet-Balance← resThe customer's prepaid wallet balance after the call (present only when the customer carries a wallet).
X-Ringside-Wallet-Deducted← resAmount debited from the customer wallet for this call.

Response fields

NameTypeDescription
idstringCustomer id (cus_*).
external_idstring | nullThe external_id you set, or null.
display_namestring | nullThe display name, or null.
statusstringactive | archived.
monthly_budget_usdnumber | nullBudget ceiling, or null if none.
rpm_limitinteger | nullRequests-per-minute cap, or null.
tpm_limitinteger | nullTokens-per-minute cap, or null.
default_billable_markup_pctnumber | nullMarkup percent, or null.
default_billable_amount_usdnumber | nullFlat billable amount, or null.
wallet_balance_usdnumber | nullPrepaid wallet balance, or null if no wallet.
lifetime_spend_usdnumberTotal attributed spend to date.
created_atstringISO 8601 timestamp (a string, not a unix integer).

Errors

  • 401missing_tokenNo Authorization header was sent.
  • 401invalid_auth_schemeThe scheme was neither Bearer nor Client.
  • 401invalid_token_formatA Bearer token not prefixed ko_.
  • 401invalid_tokenThe API key is unknown, revoked or expired.
  • 403insufficient_scopeThe key is valid but lacks the required scope.
  • 400invalid_rpm_limitrpm_limit must be a positive integer.
  • 400invalid_tpm_limittpm_limit must be a positive integer.
  • 400invalid_monthly_budget_usdmonthly_budget_usd must be a non-negative number.
  • 400invalid_default_billable_markup_pctMust be a non-negative number.
  • 400invalid_default_billable_amount_usdMust be a non-negative number.
  • 400billable_defaults_mutexmarkup_pct and amount_usd are mutually exclusive — set at most one.
  • 400metadata_too_largemetadata exceeds 4 KB serialized.
  • 404resource_not_foundNo customer with that id or external_id. Also returned for cross-tenant access, so ids are not enumerable.

See the full error reference.

Related routes

GET/v1/customersList customers (cursor pagination + the query filters above).
GET/v1/customers/:idRetrieve one. Accepts ext:<external_id> as the id.
PATCH/v1/customers/:idUpdate display_name, budgets, limits, billable defaults, status or metadata.
DELETE/v1/customers/:idArchive the customer (status becomes archived).
GET/v1/customers/:id/walletPrepaid wallet balance + full transaction history.
POST/v1/customers/:id/wallet/topupAdd credit to the customer wallet.
POST/v1/customers/:id/wallet/adjustManual balance adjustment (credit or debit).
GET/v1/customers/:id/usageUsage + cost rollups for this customer.
GET/v1/customers/:id/marginBillable vs raw cost (your margin) for this customer.
POST/v1/customers/:id/client_tokensMint a browser Client Token scoped to this customer.
POST/v1/customers/:id/client_tokens/revoke_allRevoke every active token for this customer.
DELETE/v1/customers/:id/client_tokens/:jtiRevoke one token by its jti.
GET/v1/customers/:id/conversationsList this customer's stateful conversations.

Notes

  • ·Every id route also accepts ext:<external_id> in place of the cus_ id — e.g. GET /v1/customers/ext:tenant_42/wallet — so you never have to store our id if you keep your own.
  • ·default_billable_markup_pct and default_billable_amount_usd are mutually exclusive: set one to control what the customer is billed per call, or neither to bill raw cost.
  • ·Cross-tenant access returns 404, not 403, so customer ids cannot be probed for existence.
  • ·All body fields are optional on create; a bare POST /v1/customers makes an unnamed customer you can attribute spend to immediately.

Examples