billing
Billing tells an organization what it spends, on what, and who spent it: usage recorded on meters is priced from a rate card per billing account and month, the…
Billing tells an organization what it spends, on what, and who spent it: usage recorded on meters is priced from a
rate card per billing account and month, then shared out to the people, agents, teams, departments and projects that
produced it. Budgets alert and can refuse usage, and the platform issues monthly invoices (statements) with credit
applied. Invoicing works like Stripe or Orb: drafts, finalized, paid, uncollectible and void invoices; one-off invoice
items; payments and credit notes; plans with fees, seats and meter prices; subscriptions with trials and prorations;
coupons; payment reminders and a printable invoice. Server code records usage, takes payments and runs the jobs
through iam.billing (no credential). The repository guide is docs/billing.md.
How spend is computed
A billing account is an organization, or a tenant below it with a billing profile of its own. For each account and
month, every meter's total is priced once (tiers and free units apply to the account's total), and the cost is shared
out to the daily roll-ups of usage by quantity; for unique meters every person or agent costs the same. Reported
meters carry their own cost per event. Person, team, department and project spend therefore add up to the account's
charges. Meters an account defines for itself are chargeback only (internal) and never appear on a statement.
Usage is attributed when it is recorded: the identity, its direct teams (split evenly by default, see the billing
option teamAttribution), and its department (or its first team's). An agent's usage counts toward its sponsor's
teams and department. Money is in micros of the deployment currency (costMicros), with rounded amount fields in
currency units.
Permissions
iam:billing:read reads spend, budgets, credits, profiles, invoices, plans, subscriptions and discounts;
iam:billing:manage defines meters and prices in the tenant, budgets and profiles, and lets an account's billing
managers subscribe to self-serve plans and redeem coupon codes; iam:billing:record records usage. Resources are
iam/billing, iam/billing/meters/{key}, iam/billing/budgets, iam/billing/profile, iam/billing/credits,
iam/billing/statements, iam/billing/invoice-items, iam/billing/plans, iam/billing/subscriptions,
iam/billing/coupons and iam/billing/discounts. Credits, closing a month, invoice items, payments, credit notes,
plans and coupons are for root administrators only; they act on any account's invoice by calling on the root tenant.
| Method | What it does | Access |
|---|---|---|
accounts | Lists the billing accounts in the tenant's subtree with this month's billable spend, projection, available credit and latest statement. | Credential |
anomalies | Lists the people, teams and meters whose spend on one day jumped far above their usual daily spend. | Credential |
cancelSubscription | Cancels a subscription at the end of the month (default) or now. | Credential |
changePlan | Moves a subscription to another plan now, keeping its seats and what is left of its trial. | Credential |
check | Reports whether the caller's own usage is within every enforced budget that covers it. | Credential |
closePeriod | Issues statements for a month that has ended, for every billing account or only accountId's. | Credential |
createBudget | Creates a spend budget for the tenant, a tenant below it, a team, a department or a person, per month, quarter or year. | Credential |
createCoupon | Creates a coupon accounts can redeem by code. | Credential |
createCreditNote | Issues a credit note against a finalized, paid or uncollectible invoice. | Credential |
createInvoiceItem | Adds a one-off charge, or with a negative amount a credit, to the billing account's next invoice. | Credential |
createMeter | Defines a usage meter: a platform meter on the root tenant, a chargeback meter for the tenant's subtree elsewhere. | Credential |
createPlan | Defines a plan on the platform (root) tenant. | Credential |
deactivateCoupon | Stops a coupon (by code) from being redeemed; accounts that redeemed it keep their discount. | Credential |
deleteBudget | Deletes a budget and its alert history. | Credential |
deleteInvoiceItem | Deletes a pending invoice item. | Credential |
deleteMeter | Deletes a meter that has never recorded usage, with its prices. | Credential |
deleteProfile | Removes a billing profile, so the tenant's usage rolls into its parent's account again. | Credential |
departmentSpend | Reports a department's spend, with the departments below it, grouped by identity by default. | Credential |
exportSpend | Returns a spend report as a CSV file: one row per group with the amount, share, events and a column per meter's quantity. | Credential |
exportStatement | Returns a statement as a CSV file: its lines, credit and total, then the breakdown by project, team, department and person. | Credential |
finalizeInvoice | Finalizes a draft invoice: recomputes it with the latest usage and invoice items, numbers it, seals it and emails it. | Credential |
getProfile | Returns the billing profile of the tenant (or of targetTenantId below it) and the account that pays for it. | Credential |
getStatement | Returns one statement with its lines, credit, breakdown and bill-to details, re-checking its content hash. | Credential |
getTerms | Returns the contract terms of the tenant's billing account: discount, minimum monthly commitment and tax. | Credential |
grantCredit | Grants credit to a billing account, which its statements draw on, earliest expiry first. | Credential |
listBudgets | Lists the tenant's budgets with their spend, projection and the thresholds reached in the current window. | Credential |
listCoupons | Lists the platform's coupons, newest first, with their redemptions. | Credential |
listCreditNotes | Lists the credit notes of the billing accounts in the tenant's subtree, or of one statementId, newest first. | Credential |
listCredits | Lists the credit of the tenant's billing account with the available balance. | Credential |
listDiscounts | Lists the discounts (redeemed coupons) of the billing accounts in the tenant's subtree. | Credential |
listInvoiceItems | Lists invoice items of the billing accounts in the tenant's subtree, newest first, optionally by status. | Credential |
listMeters | Lists the meters that reach the tenant with the price that applies to its billing account this month. | Credential |
listPlans | Lists the platform's plans with their fees, seats and meter prices. | Credential |
listPrices | Returns a meter's rate card as the tenant may see it, and the entry that prices its account this month. | Credential |
listStatements | Lists the statements of the billing accounts in the tenant's subtree (all of them for the root), newest month first. | Credential |
listSubscriptions | Lists the subscriptions of the billing accounts in the tenant's subtree, newest first. | Credential |
listUsage | Lists raw usage events recorded in the tenant for a month, newest first. | Credential |
markPaid | Marks a finalized or uncollectible statement paid by recording a manual payment of the amount due, with an optional reference. | Credential |
markUncollectible | Writes a finalized invoice off as uncollectible; a later payment still settles it. | Credential |
mySpend | Reports the caller's own spend: their usage and that of the agents they sponsor, with the budgets set on them. | Credential |
previewStatement | Builds the statement a billing account would receive for a month (the current one so far by default), without issuing it. | Credential |
quote | Prices a quantity of a meter as a month total for the tenant's billing account. | Credential |
record | Records usage of a meter in the tenant, attributed to an identity, their teams and department, with optional tags. | Credential |
recordMany | Records up to 100 usage events in one transaction, all or nothing. | Credential |
recordPayment | Records a payment against a finalized or uncollectible invoice. | Credential |
redeemCoupon | Redeems a coupon code for the billing account. | Credential |
removeDiscount | Ends a billing account's discount now. | Credential |
renderInvoice | Returns an invoice as a standalone HTML page to print or save as PDF. | Credential |
resumeSubscription | Undoes a cancellation at the end of the month before it takes effect. | Credential |
revokeCredit | Withdraws what is left of a credit. | Credential |
setPrice | Sets or removes a rate-card price for a meter the tenant defines: its list price, or a negotiated price for a tenant below it. | Credential |
setProfile | Creates or updates a billing profile: company, billing emails, tax ID, address, purchase order, cost center, payment terms. | Credential |
setTerms | Sets a billing account's contract terms: a discount off the subtotal, a minimum monthly commitment, and the tax invoices add. | Credential |
spend | Reports the spend of the tenant and every tenant below it for a month, grouped and filtered. | Credential |
subscribe | Subscribes the billing account to a plan (id or key). | Credential |
teamSpend | Reports a team's spend, with the teams below it, grouped by identity by default. | Credential |
trend | Returns monthly totals for the last months months (1 to 24, default 6), with the filters of spend. | Credential |
updateBudget | Changes a budget's name, amount, period, meters, thresholds, alerts or enforcement; its subject stays. | Credential |
updateMeter | Renames a meter, changes its unit or description, or archives it. | Credential |
updatePlan | Changes a plan, by id or key: name, items, description, trial, self-serve, archived. | Credential |
updateSubscription | Changes a subscription's seats. | Credential |
voidStatement | Voids a finalized statement: its credit, invoice items, coupons and advance-billed months come back and the month reopens. | Credential |
accounts
Lists the billing accounts in the tenant's subtree with this month's billable spend, projection, available credit and latest statement.
- Permission:
iam:billing:readoniam/billing. - Audited as:
iam:billing:read.
On the root tenant this is every organization: the platform's receivables view. monthToDateMicros counts only
meters defined above the account (what a statement would bill); totalMicros includes the account's own chargeback
meters.
Prop
Type
An array of AccountOverview.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/accounts" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.accounts(
credential: CredentialInput,
input: { tenantId: string },
): Promise<AccountOverview[]>anomalies
Lists the people, teams and meters whose spend on one day jumped far above their usual daily spend.
- Permission:
iam:billing:readoniam/billing. - Audited as:
iam:billing:read. - Errors:
INVALID_INPUTfor a malformedday,baselineDaysoutside 3 to 90,factoroutside 1.1 to 1000, or a negativeminimum.
day defaults to yesterday in the billing time zone. A spike is spend at least factor (3) times the average over the
baselineDays (14) before it and at least minimum (10 currency units) more; spending with no baseline counts when it
reaches minimum (factor: null). The largest increases come first, at most 50. The daily job
iam.billing.detectAnomalies() alerts on them once each (billing:anomaly, spend-anomaly email).
const { anomalies } = await iam.api.billing.anomalies(admin, { tenantId, factor: 5 });Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/anomalies" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.anomalies(
credential: CredentialInput,
input: { tenantId: string } & AnomalyOptions,
): Promise<{ tenantId: string; anomalies: SpendAnomaly[] }>cancelSubscription
Cancels a subscription at the end of the month (default) or now.
- Permission:
iam:billing:manageoniam/billing/subscriptions(self-serve plans, at the month's end only), or a root administrator. - Audited as:
billing:subscription-cancel. - Errors:
ACCESS_DENIED(403) for an immediate cancellation by anyone but a root administrator;INVALID_TRANSITION(409) for an ended subscription.
At the month's end the subscription keeps running and resumeSubscription can undo it. With atPeriodEnd: false it
ends now and the unused part of this month's advance fees and seats is credited as invoice items; arrears items bill
the part of the month it ran.
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/cancelSubscription" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"subscriptionId": "<subscriptionId>"
}'iam.api.billing.cancelSubscription(
credential: CredentialInput,
input: { tenantId: string; subscriptionId: string; atPeriodEnd?: boolean },
): Promise<{ subscription: SubscriptionView; invoiceItems: InvoiceItemView[] }>changePlan
Moves a subscription to another plan now, keeping its seats and what is left of its trial.
- Permission:
iam:billing:manageoniam/billing/subscriptionswhen both plans are self-serve, or a root administrator. - Audited as:
billing:subscription-plan-change. - Errors:
CONFLICT(409) when the account already subscribes to the new plan;INVALID_TRANSITION(409) for an ended subscription or an archived plan;INVALID_INPUTfor the same plan.
The old subscription ends and a new one starts. The old plan's unused advance charges are credited and the new plan's
charges for the rest of the month added, both as invoice items for the next invoice (invoiceItems).
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/changePlan" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"subscriptionId": "<subscriptionId>",
"plan": "<plan>"
}'iam.api.billing.changePlan(
credential: CredentialInput,
input: { tenantId: string; subscriptionId: string; plan: string },
): Promise<{ subscription: SubscriptionView; invoiceItems: InvoiceItemView[] }>check
Reports whether the caller's own usage is within every enforced budget that covers it.
- Permission: The caller's own session; the tenant must be the caller's tenant or one below it.
- Audited as: not audited.
- Errors:
ACCESS_DENIED(403) for a tenant outside the caller's.
Covering budgets are enforced tenant budgets on the tenant or an ancestor, and the caller's own, their teams' (with
parent teams) and their department's (with the departments above it); meter narrows to budgets that count it.
blockedBy names the first spent budget. Statuses may lag recorded usage by up to 30 seconds. Server code checks any
identity with iam.billing.check.
const verdict = await client.billing.check({ tenantId, meter: 'api-calls' });
if (!verdict.allowed) showBudgetBanner(verdict.blockedBy);Prop
Type
A SpendCheck object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/check" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.check(
credential: CredentialInput,
input: { tenantId: string; meter?: string },
): Promise<SpendCheck>closePeriod
Issues statements for a month that has ended, for every billing account or only accountId's.
- Permission: Root administrators only, called on the root tenant (
iam:billing:manageoniam/billing/periods). - Audited as:
iam:billing:manage; each statement asbilling:statement. - Errors:
INVALID_INPUTfor the current or a future month, or when called on another tenant.
period defaults to last month. Each invoice bills the month's usage of platform meters, the subscriptions' fees
and seats (the month itself for arrears items, the next month for advance ones), and pending invoice items. Accounts
already invoiced for the month and accounts with nothing to bill are skipped (skipped.existing, skipped.empty), so
the job is safe to repeat. Coupons apply after the contract discount, credit earliest expiry first; invoices are
emailed (billing-statement) to the profile's billing emails or the owners, and raw usage events past their retention
are deleted (sweptUsage). With draft: true (or the option billing.autoFinalize: false) invoices are kept as
drafts, refreshed on every run, and listed in drafted; finalize them with finalizeInvoice. Schedulers call
iam.billing.closePeriod() instead.
Prop
Type
A ClosePeriodResult object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/closePeriod" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.closePeriod(
credential: CredentialInput,
input: { tenantId: string; period?: string; accountId?: string; draft?: boolean },
): Promise<ClosePeriodResult>createBudget
Creates a spend budget for the tenant, a tenant below it, a team, a department or a person, per month, quarter or year.
Used inBilling and spend
- Permission:
iam:billing:manageoniam/billing/budgets. - Audited as:
billing:budget-create. - Errors:
CONFLICT(409) for a name already used (case-insensitive);LIMIT_EXCEEDED(409) past 200 budgets;NOT_FOUNDfor a subject outside the tenant;INVALID_INPUTfor an amount of 0, a malformed meter key, more than 10 thresholds or notification addresses.
amount is in currency units. thresholds (default 50, 80, 100 percent) and forecastAlerts (default on) drive the
alerts that iam.billing.checkBudgets() sends once per window to the owners, the subject (the person, the team's
maintainers or the department head) and notify.emails. enforce makes covered usage fail once the budget is spent.
The result is the budget with its current standing.
await iam.api.billing.createBudget(admin, {
tenantId,
name: 'Platform team monthly',
subjectType: 'team',
subjectId: platformTeamId,
amount: 600,
notify: { emails: ['finance@acme.test'] },
});Prop
Type
A BillingBudgetView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/createBudget" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"name": "<name>",
"amount": 1
}'iam.api.billing.createBudget(
credential: CredentialInput,
input: { tenantId: string } & BillingBudgetInput,
): Promise<BillingBudgetView>createCoupon
Creates a coupon accounts can redeem by code.
- Permission: Root administrators only (
iam:billing:manageoniam/billing/coupons), called on the root tenant. - Audited as:
billing:coupon. - Errors:
CONFLICT(409) for a code already used;INVALID_INPUTfor a code that is not 3 to 32 letters, digits,-or_, both or neither ofpercentOffandamountOff, a percentage outside 0 to 100,durationInMonthswithoutduration: 'repeating', or aredeemByin the past.
Codes are stored in upper case. duration is once (default: the next invoice), repeating (invoices for
durationInMonths months from the month of redemption) or forever. maxRedemptions caps how many accounts may
redeem it.
await iam.api.billing.createCoupon(root, {
tenantId: rootTenantId,
code: 'LAUNCH20',
percentOff: 20,
duration: 'repeating',
durationInMonths: 3,
});Prop
Type
A CouponView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/createCoupon" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"code": "<code>"
}'iam.api.billing.createCoupon(
credential: CredentialInput,
input: {
tenantId: string;
code: string;
name?: string;
percentOff?: number;
amountOff?: number;
duration?: BillingCoupon['duration'];
durationInMonths?: number;
maxRedemptions?: number;
redeemBy?: number;
},
): Promise<CouponView>createCreditNote
Issues a credit note against a finalized, paid or uncollectible invoice.
- Permission: Root administrators only (
iam:billing:manageoniam/billing/statements). - Audited as:
billing:credit-note. - Errors:
INVALID_INPUTfor an amount above what is left to credit, an unknownreason, or a non-booleanrefund;INVALID_TRANSITION(409) for a draft or void invoice.
amount defaults to everything not yet credited. The note first reduces the amount due; the rest (a part already
paid) becomes account credit, or with refund: true is recorded as refunded outside Better IAM. applied shows the
split. Notes are numbered {invoice}-CN-01, -CN-02, ...; reason is duplicate, fraudulent, order_change,
product_unsatisfactory or other (default), with an optional memo. An invoice the notes and payments cover is paid.
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/createCreditNote" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"statementId": "<statementId>"
}'iam.api.billing.createCreditNote(
credential: CredentialInput,
input: {
tenantId: string;
statementId: string;
amount?: number;
reason?: BillingCreditNote['reason'];
memo?: string;
refund?: boolean;
},
): Promise<{ statement: StatementSummary; creditNote: CreditNoteView }>createInvoiceItem
Adds a one-off charge, or with a negative amount a credit, to the billing account's next invoice.
- Permission: Root administrators only (
iam:billing:manageoniam/billing/invoice-items), called on the account. - Audited as:
billing:invoice-item. - Errors:
INVALID_INPUTwhen the tenant is not a billing account, for an empty description, an amount beyond one billion, a quantity of 0, or more than 20 metadata entries;BILLING_PERIOD_CLOSED(409) for aperiodalready invoiced.
amount is per unit in currency units and quantity defaults to 1; the item's total is rounded to the cent. period
bills it on the invoice for that month instead of the next one. When credit items exceed an invoice's charges the
invoice totals 0 and the rest becomes account credit.
await iam.api.billing.createInvoiceItem(root, {
tenantId: acmeId,
description: 'Onboarding workshop',
amount: 500,
});Prop
Type
A InvoiceItemView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/createInvoiceItem" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"description": "<description>",
"amount": 1
}'iam.api.billing.createInvoiceItem(
credential: CredentialInput,
input: {
tenantId: string;
description: string;
amount: number;
quantity?: number;
period?: string;
metadata?: Record<string, string>;
},
): Promise<InvoiceItemView>createMeter
Defines a usage meter: a platform meter on the root tenant, a chargeback meter for the tenant's subtree elsewhere.
Used inBilling and spend
- Permission:
iam:billing:manageoniam/billing/meters/{key}. - Audited as:
billing:meter-create. - Errors:
CONFLICT(409) when a meter with the key already reaches the tenant;LIMIT_EXCEEDED(409) past 100 meters;INVALID_INPUTfor a malformed key or auniquereported meter.
Keys are 1 to 64 lowercase letters, digits, dots, underscores or hyphens, starting with a letter. aggregation is
sum (default) or unique (distinct people and agents per month); pricing is rate-card (default) or reported
(each event carries its cost). Neither can change later.
Prop
Type
A MeterView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/createMeter" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"key": "<key>",
"name": "<name>"
}'iam.api.billing.createMeter(
credential: CredentialInput,
input: {
tenantId: string;
key: string;
name: string;
unit?: string;
description?: string;
aggregation?: BillingMeter['aggregation'];
pricing?: BillingMeter['pricing'];
},
): Promise<MeterView>createPlan
Defines a plan on the platform (root) tenant.
Used inBilling and spend
- Permission: Root administrators only (
iam:billing:manageoniam/billing/plans), called on the root tenant. - Audited as:
billing:plan. - Errors:
CONFLICT(409) for a key already used;LIMIT_EXCEEDED(409) past 100 plans;INVALID_INPUTfor a malformed key, 0 or more than 20 items, duplicate item ids, two items pricing one meter, or a malformed price.
items are fee (amount per month), seat (unitAmount per seat and month, includedSeats), both billed in
advance (default) or arrears, and usage (meter with a price that replaces the rate card for subscribers).
trialDays (1 to 365) starts subscriptions with a free trial; selfServe lets account billing managers subscribe.
await iam.api.billing.createPlan(root, {
tenantId: rootTenantId,
key: 'team',
name: 'Team',
selfServe: true,
items: [
{ id: 'platform', kind: 'fee', name: 'Platform fee', amount: 99 },
{ id: 'seats', kind: 'seat', name: 'Seats', unitAmount: 12, includedSeats: 3 },
],
});Prop
Type
A PlanView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/createPlan" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"key": "<key>",
"name": "<name>",
"items": [
{}
]
}'iam.api.billing.createPlan(
credential: CredentialInput,
input: {
tenantId: string;
key: string;
name: string;
items: unknown[];
description?: string;
trialDays?: number;
selfServe?: boolean;
},
): Promise<PlanView>deactivateCoupon
Stops a coupon (by code) from being redeemed; accounts that redeemed it keep their discount.
- Permission: Root administrators only (
iam:billing:manageoniam/billing/coupons), called on the root tenant. - Audited as:
billing:coupon-deactivate. - Errors:
NOT_FOUNDfor an unknown code.
Prop
Type
A CouponView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/deactivateCoupon" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"code": "<code>"
}'iam.api.billing.deactivateCoupon(
credential: CredentialInput,
input: { tenantId: string; code: string },
): Promise<CouponView>deleteBudget
Deletes a budget and its alert history.
- Permission:
iam:billing:manageoniam/billing/budgets. - Audited as:
billing:budget-delete. - Errors:
NOT_FOUNDfor a budget of another tenant.
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/deleteBudget" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"budgetId": "<budgetId>"
}'iam.api.billing.deleteBudget(
credential: CredentialInput,
input: { tenantId: string; budgetId: string },
): Promise<{ success: true }>deleteInvoiceItem
Deletes a pending invoice item.
- Permission: Root administrators only (
iam:billing:manageoniam/billing/invoice-items), called on the account. - Audited as:
billing:invoice-item-delete. - Errors:
INVALID_TRANSITION(409) for an item already on a finalized invoice (issue a credit note instead).
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/deleteInvoiceItem" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"itemId": "<itemId>"
}'iam.api.billing.deleteInvoiceItem(
credential: CredentialInput,
input: { tenantId: string; itemId: string },
): Promise<{ success: true }>deleteMeter
Deletes a meter that has never recorded usage, with its prices.
- Permission:
iam:billing:manageoniam/billing/meters/{key}. - Audited as:
billing:meter-delete. - Errors:
RESOURCE_IN_USE(409) once the meter has recorded usage (archive it withupdateMeterinstead);NOT_FOUNDwhen the tenant does not define the key.
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/deleteMeter" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"key": "<key>"
}'iam.api.billing.deleteMeter(
credential: CredentialInput,
input: { tenantId: string; key: string },
): Promise<{ success: true; removedPrices: number }>deleteProfile
Removes a billing profile, so the tenant's usage rolls into its parent's account again.
- Permission:
iam:billing:manageoniam/billing/profile; below an organization, called from an ancestor withtargetTenantId. - Audited as:
billing:profile-delete. - Errors:
NOT_FOUNDwithout a profile;ACCESS_DENIED(403) when a tenant below an organization removes its own.
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/deleteProfile" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.deleteProfile(
credential: CredentialInput,
input: { tenantId: string; targetTenantId?: string },
): Promise<{ success: true }>departmentSpend
Reports a department's spend, with the departments below it, grouped by identity by default.
- Permission: The department's head (or the head of a department above it), or
iam:billing:read. - Audited as:
iam:billing:read, withmetadata.viadepartment-headorpermission. - Errors:
ACCESS_DENIED(403) for anyone else;NOT_FOUNDfor a department outside the tenant.
Prop
Type
A SpendReport object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/departmentSpend" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"departmentId": "<departmentId>"
}'iam.api.billing.departmentSpend(
credential: CredentialInput,
input: {
tenantId: string;
departmentId: string;
period?: string;
groupBy?: SpendGroupBy;
},
): Promise<SpendReport>exportSpend
Returns a spend report as a CSV file: one row per group with the amount, share, events and a column per meter's quantity.
- Permission:
iam:billing:readoniam/billing. - Audited as:
iam:billing:read. - Errors: as
spend.
It takes the same input as spend and returns filename, contentType and body (RFC 4180, CRLF line endings, a
final total row). Cells that a spreadsheet would run as a formula are prefixed with a quote.
Prop
Type
A CsvExport object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/exportSpend" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.exportSpend(
credential: CredentialInput,
input: { tenantId: string } & SpendQuery,
): Promise<CsvExport>exportStatement
Returns a statement as a CSV file: its lines, credit and total, then the breakdown by project, team, department and person.
- Permission:
iam:billing:readoniam/billing/statements; the statement's account must be the tenant or below it. - Audited as:
iam:billing:read. - Errors:
NOT_FOUNDfor a statement outside the tenant's subtree.
The file is named after the statement number. Department rows carry their cost center.
Prop
Type
A CsvExport object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/exportStatement" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"statementId": "<statementId>"
}'iam.api.billing.exportStatement(
credential: CredentialInput,
input: { tenantId: string; statementId: string },
): Promise<CsvExport>finalizeInvoice
Finalizes a draft invoice: recomputes it with the latest usage and invoice items, numbers it, seals it and emails it.
- Permission: Root administrators only (
iam:billing:manageoniam/billing/statements), called on the account or the root tenant. - Audited as:
billing:statement-finalizeandbilling:statement. - Errors:
INVALID_TRANSITION(409) for an invoice that is not a draft, or a draft with nothing left to bill.
The invoice then consumes its credit, marks its invoice items invoiced, its subscriptions' advance months billed, and
its coupons used. An invoice with nothing to pay is paid on issue.
Prop
Type
A StatementSummary object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/finalizeInvoice" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"statementId": "<statementId>"
}'iam.api.billing.finalizeInvoice(
credential: CredentialInput,
input: { tenantId: string; statementId: string },
): Promise<StatementSummary>getProfile
Returns the billing profile of the tenant (or of targetTenantId below it) and the account that pays for it.
- Permission:
iam:billing:readoniam/billing/profile. - Audited as:
iam:billing:read.
account.inherited is true when an ancestor pays; profile is null without a profile of its own.
Prop
Type
A ProfileView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/getProfile" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.getProfile(
credential: CredentialInput,
input: { tenantId: string; targetTenantId?: string },
): Promise<ProfileView>getStatement
Returns one statement with its lines, credit, breakdown and bill-to details, re-checking its content hash.
- Permission:
iam:billing:readoniam/billing/statements; the statement's account must be the tenant or below it. - Audited as:
iam:billing:read. - Errors:
NOT_FOUNDfor a statement outside the tenant's subtree.
verified is false when the stored content no longer matches the hash computed at issue. overdue is true for a
finalized statement past its due date.
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/getStatement" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"statementId": "<statementId>"
}'iam.api.billing.getStatement(
credential: CredentialInput,
input: { tenantId: string; statementId: string },
): Promise<{
total: number;
overdue: boolean;
verified: boolean;
number: string;
status: InvoiceStatus;
issuedAt: number;
dueAt: number;
hash: string;
payments?: InvoicePayment[];
amountPaidMicros?: number;
creditNotesMicros?: number;
invoiceItemIds?: string[];
advanceBilled?: { subscriptionId: string; period: string }[];
carryForward?: { creditId: string; amountMicros: number };
reminders?: { days: number; at: number; recipients: number }[];
paidAt?: number;
paidBy?: string;
paymentReference?: string;
voidedAt?: number;
voidedBy?: string;
voidReason?: string;
markedUncollectibleAt?: number;
id: string;
tenantId: string;
uniqueKey?: string;
period: string;
currency: string;
periodStart: number;
periodEnd: number;
lines: StatementLine[];
billingReason?: 'period' | 'subscription' | 'manual';
subtotalMicros: number;
coupons?: { discountId: string; code: string; name: string; amountMicros: number }[];
discount?: { percent: number; amountMicros: number };
commitment?: { minimumMicros: number; trueUpMicros: number };
creditsMicros: number;
creditsApplied: { creditId: string; amountMicros: number }[];
tax?: { label: string; ratePercent: number; amountMicros: number };
totalMicros: number;
breakdown: {
tenants: StatementAllocation[];
teams: StatementAllocation[];
departments: (StatementAllocation & { costCenter?: string })[];
identities: StatementAllocation[];
};
billTo: {
name: string;
companyName?: string;
taxId?: string;
address?: string;
purchaseOrder?: string;
costCenter?: string;
emails: string[];
};
}>getTerms
Returns the contract terms of the tenant's billing account: discount, minimum monthly commitment and tax.
- Permission:
iam:billing:readoniam/billing/terms. - Audited as:
iam:billing:read.
When an ancestor pays for the tenant the result only says inherited: true; without terms it lists none.
Prop
Type
A TermsView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/getTerms" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.getTerms(
credential: CredentialInput,
input: { tenantId: string },
): Promise<TermsView>grantCredit
Grants credit to a billing account, which its statements draw on, earliest expiry first.
- Permission: Root administrators only (
iam:billing:manageoniam/billing/credits). - Audited as:
billing:credit-grant. - Errors:
INVALID_INPUTwhen the tenant is not a billing account (an organization or a tenant with a profile), for an amount of 0, or anexpiresAtin the past.
await iam.api.billing.grantCredit(root, { tenantId: acmeId, amount: 100, reason: 'Launch promotion' });Prop
Type
A CreditView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/grantCredit" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"amount": 1,
"reason": "<reason>"
}'iam.api.billing.grantCredit(
credential: CredentialInput,
input: { tenantId: string; amount: number; reason: string; expiresAt?: number },
): Promise<CreditView>listBudgets
Lists the tenant's budgets with their spend, projection and the thresholds reached in the current window.
- Permission:
iam:billing:readoniam/billing/budgets. - Audited as:
iam:billing:read.
Prop
Type
An array of BillingBudgetView.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/listBudgets" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.listBudgets(
credential: CredentialInput,
input: { tenantId: string },
): Promise<BillingBudgetView[]>listCoupons
Lists the platform's coupons, newest first, with their redemptions.
- Permission: Root administrators only (
iam:billing:readoniam/billing/coupons), called on the root tenant. - Audited as:
iam:billing:read.
active is false for deactivated coupons, those past redeemBy, and those out of redemptions.
Prop
Type
An array of CouponView.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/listCoupons" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.listCoupons(
credential: CredentialInput,
input: { tenantId: string },
): Promise<CouponView[]>listCreditNotes
Lists the credit notes of the billing accounts in the tenant's subtree, or of one statementId, newest first.
- Permission:
iam:billing:readoniam/billing/statements. - Audited as:
iam:billing:read.
Prop
Type
An array of CreditNoteView.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/listCreditNotes" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.listCreditNotes(
credential: CredentialInput,
input: { tenantId: string; statementId?: string },
): Promise<CreditNoteView[]>listCredits
Lists the credit of the tenant's billing account with the available balance.
- Permission:
iam:billing:readoniam/billing/credits. - Audited as:
iam:billing:read.
When an ancestor pays for the tenant the list is empty and inherited is true.
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/listCredits" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.listCredits(
credential: CredentialInput,
input: { tenantId: string },
): Promise<{
accountId: string;
inherited: boolean;
balanceMicros: number;
balance: number;
credits: CreditView[];
}>listDiscounts
Lists the discounts (redeemed coupons) of the billing accounts in the tenant's subtree.
- Permission:
iam:billing:readoniam/billing/discounts. - Audited as:
iam:billing:read.
appliedInvoices counts the invoices a discount reduced; active says whether it applies to this month's invoice.
Prop
Type
An array of DiscountView.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/listDiscounts" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.listDiscounts(
credential: CredentialInput,
input: { tenantId: string },
): Promise<DiscountView[]>listInvoiceItems
Lists invoice items of the billing accounts in the tenant's subtree, newest first, optionally by status.
- Permission:
iam:billing:readoniam/billing/invoice-items. - Audited as:
iam:billing:read. - Errors:
INVALID_INPUTfor astatusother thanpendingorinvoiced.
pending items wait for the account's next invoice (or the one for their period); invoiced items carry the
statementId that billed them. source: 'proration' items come from subscription changes.
Prop
Type
An array of InvoiceItemView.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/listInvoiceItems" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.listInvoiceItems(
credential: CredentialInput,
input: { tenantId: string; status?: BillingInvoiceItem['status'] },
): Promise<InvoiceItemView[]>listMeters
Lists the meters that reach the tenant with the price that applies to its billing account this month.
- Permission:
iam:billing:readoniam/billing. - Audited as:
iam:billing:read.
scope is platform for root meters; inherited marks meters an ancestor defines.
Prop
Type
An array of MeterView.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/listMeters" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.listMeters(
credential: CredentialInput,
input: { tenantId: string },
): Promise<MeterView[]>listPlans
Lists the platform's plans with their fees, seats and meter prices.
- Permission:
iam:billing:readoniam/billing/plans. - Audited as:
iam:billing:read.
Tenants see plans that are not archived. Root administrators on the root tenant also get subscribers (live
subscriptions) and, with includeArchived, archived plans. Amounts are in currency units.
Prop
Type
An array of PlanView.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/listPlans" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.listPlans(
credential: CredentialInput,
input: { tenantId: string; includeArchived?: boolean },
): Promise<PlanView[]>listPrices
Returns a meter's rate card as the tenant may see it, and the entry that prices its account this month.
- Permission:
iam:billing:readoniam/billing/meters/{key}. - Audited as:
iam:billing:read. - Errors:
NOT_FOUNDwhen no meter with the key reaches the tenant.
Entries for the tenant, its ancestors (list prices) and tenants below it are listed, newest first; negotiated prices for other organizations are not.
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/listPrices" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"meter": "<meter>"
}'iam.api.billing.listPrices(
credential: CredentialInput,
input: { tenantId: string; meter: string },
): Promise<{ effective?: PriceView | undefined; meter: MeterView; entries: PriceView[] }>listStatements
Lists the statements of the billing accounts in the tenant's subtree (all of them for the root), newest month first.
- Permission:
iam:billing:readoniam/billing/statements. - Audited as:
iam:billing:read.
Filter by status (finalized, paid, void) or period.
Prop
Type
An array of StatementSummary.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/listStatements" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.listStatements(
credential: CredentialInput,
input: { tenantId: string; status?: BillingStatement['status']; period?: string },
): Promise<StatementSummary[]>listSubscriptions
Lists the subscriptions of the billing accounts in the tenant's subtree, newest first.
- Permission:
iam:billing:readoniam/billing/subscriptions. - Audited as:
iam:billing:read.
Ended subscriptions are left out unless includeEnded. status is trialing, active or ended; billedAdvance
lists the months already billed in advance.
Prop
Type
An array of SubscriptionView.
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/listSubscriptions" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.listSubscriptions(
credential: CredentialInput,
input: { tenantId: string; includeEnded?: boolean },
): Promise<SubscriptionView[]>listUsage
Lists raw usage events recorded in the tenant for a month, newest first.
- Permission:
iam:billing:readoniam/billing. - Audited as:
iam:billing:read.
Only the tenant itself (not its subtree), at most limit (1 to 500, default 100) events, optionally for one meter
or identity. Events are kept usageRetentionDays after their month; reports use daily roll-ups and outlive them.
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/listUsage" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.listUsage(
credential: CredentialInput,
input: {
tenantId: string;
period?: string;
meter?: string;
identityId?: string;
limit?: number;
},
): Promise<{
tenantId: string;
period: string;
events: {
idempotencyKey?: string | undefined;
meterId: string;
meter: string;
quantity: number;
costMicros?: number;
identityId?: string;
agentId?: string;
teamIds: string[];
departmentId?: string;
tags?: Record<string, string>;
occurredAt: number;
period: string;
day: string;
recordedAt: number;
recordedBy: string;
sourceId?: string;
id: string;
tenantId: string;
}[];
}>markPaid
Marks a finalized or uncollectible statement paid by recording a manual payment of the amount due, with an optional reference.
- Permission: Root administrators only (
iam:billing:manageoniam/billing/statements), called on the account or the root tenant. - Audited as:
billing:statement-paid. - Errors:
INVALID_TRANSITION(409) for a draft, paid or void statement.
Prop
Type
A StatementSummary object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/markPaid" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"statementId": "<statementId>"
}'iam.api.billing.markPaid(
credential: CredentialInput,
input: { tenantId: string; statementId: string; reference?: string },
): Promise<StatementSummary>markUncollectible
Writes a finalized invoice off as uncollectible; a later payment still settles it.
- Permission: Root administrators only (
iam:billing:manageoniam/billing/statements). - Audited as:
billing:statement-uncollectible. - Errors:
INVALID_TRANSITION(409) for an invoice that is not finalized.
Uncollectible invoices get no payment reminders.
Prop
Type
A StatementSummary object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/markUncollectible" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"statementId": "<statementId>"
}'iam.api.billing.markUncollectible(
credential: CredentialInput,
input: { tenantId: string; statementId: string },
): Promise<StatementSummary>mySpend
Reports the caller's own spend: their usage and that of the agents they sponsor, with the budgets set on them.
- Permission: The caller's own session in their own tenant.
- Audited as: not audited.
- Errors:
ACCESS_DENIED(403) for another tenant;INVALID_INPUTfor agroupByother thanmeter,day,agent,tenantortag:{name}.
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/mySpend" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.mySpend(
credential: CredentialInput,
input: { tenantId: string; period?: string; groupBy?: SpendGroupBy },
): Promise<SpendReport & { budgets: BudgetStatus[] }>previewStatement
Builds the statement a billing account would receive for a month (the current one so far by default), without issuing it.
- Permission:
iam:billing:readoniam/billing/statements. - Audited as:
iam:billing:read. - Errors:
INVALID_INPUTwhen the tenant is not a billing account.
Prop
Type
A StatementDraft object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/previewStatement" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.previewStatement(
credential: CredentialInput,
input: { tenantId: string; period?: string },
): Promise<StatementDraft>quote
Prices a quantity of a meter as a month total for the tenant's billing account.
- Permission:
iam:billing:readoniam/billing/meters/{key}. - Audited as:
iam:billing:read. - Errors:
NOT_FOUNDfor an unknown meter;INVALID_INPUTfor a reported meter or a negative quantity.
Tiers and free units apply as they would to the account's month total; unpriced is true without a price.
Prop
Type
One of object | object.
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/quote" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"meter": "<meter>",
"quantity": 1
}'iam.api.billing.quote(
credential: CredentialInput,
input: { tenantId: string; meter: string; quantity: number; period?: string },
): Promise<| {
price: PriceView;
meter: string;
quantity: number;
period: string;
currency: string;
amountMicros: number;
amount: number;
}
| {
unpriced: true;
meter: string;
quantity: number;
period: string;
currency: string;
amountMicros: number;
amount: number;
}>record
Records usage of a meter in the tenant, attributed to an identity, their teams and department, with optional tags.
- Permission:
iam:billing:recordoniam/billing/meters/{key}. - Audited as:
iam:billing:record. - Errors:
NOT_FOUNDfor an unknown meter or an identity outside the tenant and its ancestors;METER_ARCHIVED(409);BILLING_PERIOD_CLOSED(409) for a month already invoiced;SPEND_LIMIT_REACHED(402) withenforceBudgetsunder a spent enforced budget;CONFLICT(409) for an idempotency key used on another meter;INVALID_INPUTfor a negative quantity,coston a rate-card meter or none on a reported one, oroccurredAtmore than five minutes ahead or a year back.
idempotencyKey makes retries safe: a repeat returns the first receipt with duplicate: true. teamId attributes the
usage to one team instead of the person's own. Server code records without an audit event per call through
iam.billing.record, the usual choice for metering.
await client.billing.record({
tenantId,
meter: 'api-calls',
quantity: 1,
identityId,
tags: { endpoint: 'search' },
idempotencyKey: requestId,
});Prop
Type
A UsageReceipt object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/record" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"meter": "<meter>"
}'iam.api.billing.record(
credential: CredentialInput,
input: UsageInput & { enforceBudgets?: boolean },
): Promise<UsageReceipt>recordMany
Records up to 100 usage events in one transaction, all or nothing.
- Permission:
iam:billing:recordoniam/billingin the call's tenant. - Audited as:
iam:billing:record. - Errors: as
record;INVALID_INPUTfor an event outside the tenant's subtree or more than 100 events.
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/recordMany" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"events": {
"meter": "<meter>"
}
}'iam.api.billing.recordMany(
credential: CredentialInput,
input: {
tenantId: string;
events: Omit<UsageInput, 'tenantId'> & { tenantId?: string }[];
},
): Promise<{ receipts: UsageReceipt[] }>recordPayment
Records a payment against a finalized or uncollectible invoice.
- Permission: Root administrators only (
iam:billing:manageoniam/billing/statements), called on the account or the root tenant. - Audited as:
billing:payment. - Errors:
INVALID_TRANSITION(409) for a draft, paid or void invoice;INVALID_INPUTfor an amount of 0 or areceivedAtin the future.
amount (currency units) defaults to the amount due; method (default manual) and reference describe it. A
partial payment leaves the rest due; once payments and credit notes cover the invoice it is paid. A payment above
the amount due keeps the excess as account credit (payment.overpaymentMicros, payment.creditId). Payment
processors report payments through iam.billing.recordPayment({ statementId | number, amount, idempotencyKey })
instead, where the idempotency key makes webhook redelivery safe.
await iam.api.billing.recordPayment(root, {
tenantId: acmeId,
statementId,
amount: 300,
method: 'bank_transfer',
reference: 'wire-88213',
});Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/recordPayment" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"statementId": "<statementId>"
}'iam.api.billing.recordPayment(
credential: CredentialInput,
input: {
tenantId: string;
statementId: string;
amount?: number;
method?: string;
reference?: string;
receivedAt?: number;
},
): Promise<{ statement: StatementSummary; payment: InvoicePayment }>redeemCoupon
Redeems a coupon code for the billing account.
Used inBilling and spend
- Permission:
iam:billing:manageoniam/billing/discountsin the account. - Audited as:
billing:coupon-redeem. - Errors:
CONFLICT(409) when the account already redeemed the coupon;NOT_FOUNDfor a code that is unknown, inactive, pastredeemByor out of redemptions (all answer the same);INVALID_INPUTwhen the tenant is not a billing account.
The resulting discount applies to the account's invoices after the contract discount, in the order codes were redeemed. Voiding an invoice gives a one-off discount back.
Prop
Type
A DiscountView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/redeemCoupon" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"code": "<code>"
}'iam.api.billing.redeemCoupon(
credential: CredentialInput,
input: { tenantId: string; code: string },
): Promise<DiscountView>removeDiscount
Ends a billing account's discount now.
- Permission: Root administrators only (
iam:billing:manageoniam/billing/discounts), called on the account. - Audited as:
billing:discount-remove. - Errors:
INVALID_TRANSITION(409) for a discount that has already ended.
Prop
Type
A DiscountView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/removeDiscount" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"discountId": "<discountId>"
}'iam.api.billing.removeDiscount(
credential: CredentialInput,
input: { tenantId: string; discountId: string },
): Promise<DiscountView>renderInvoice
Returns an invoice as a standalone HTML page to print or save as PDF.
- Permission:
iam:billing:readoniam/billing/statements. - Audited as:
iam:billing:read. - Errors:
NOT_FOUNDfor an invoice outside the tenant's subtree.
The result is { filename, contentType, body }. The page names the issuer (the billing.issuer option: name,
address, tax ID, contact, and paymentInstructions under the totals), the bill-to details, every line with its tier
sub-lines, service period and proration, then discounts, coupons, credit, tax, payments, credit notes and the amount
due. It has no scripts and only inline styles, so it can be served with a strict content security policy.
Prop
Type
A InvoiceDocument object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/renderInvoice" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"statementId": "<statementId>"
}'iam.api.billing.renderInvoice(
credential: CredentialInput,
input: { tenantId: string; statementId: string },
): Promise<InvoiceDocument>resumeSubscription
Undoes a cancellation at the end of the month before it takes effect.
- Permission:
iam:billing:manageoniam/billing/subscriptions(self-serve plans), or a root administrator. - Audited as:
billing:subscription-resume. - Errors:
INVALID_TRANSITION(409) for a subscription that is not set to cancel, or has ended.
Prop
Type
A SubscriptionView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/resumeSubscription" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"subscriptionId": "<subscriptionId>"
}'iam.api.billing.resumeSubscription(
credential: CredentialInput,
input: { tenantId: string; subscriptionId: string },
): Promise<SubscriptionView>revokeCredit
Withdraws what is left of a credit.
- Permission: Root administrators only (
iam:billing:manageoniam/billing/credits). - Audited as:
billing:credit-revoke. - Errors:
INVALID_TRANSITION(409) for a credit already revoked.
Prop
Type
A CreditView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/revokeCredit" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"creditId": "<creditId>"
}'iam.api.billing.revokeCredit(
credential: CredentialInput,
input: { tenantId: string; creditId: string },
): Promise<CreditView>setPrice
Sets or removes a rate-card price for a meter the tenant defines: its list price, or a negotiated price for a tenant below it.
Used inBilling and spend
- Permission:
iam:billing:manageoniam/billing/meters/{key}in the defining tenant. - Audited as:
billing:price. - Errors:
NOT_FOUNDwhen the tenant does not define the meter;INVALID_INPUTfor a reported meter, a target outside the subtree, malformed tiers, oreffectiveFrommore than 12 months back;BILLING_PERIOD_CLOSED(409) when a month fromeffectiveFromon is already invoiced for the tenants it reaches.
price takes currency units: per-unit (unitAmount), graduated or volume (tiers of upTo and unitAmount,
optional flatAmount, the last upTo: null), or package (packageSize, packageAmount), each with an optional
includedQuantity. effectiveFrom (default this month) starts the price; price: null removes that entry.
await iam.api.billing.setPrice(root, {
tenantId: rootTenantId,
meter: 'api-calls',
targetTenantId: acmeId,
price: { model: 'per-unit', unitAmount: 0.0003 },
note: 'Enterprise agreement',
});Prop
Type
One of null | PriceView; the object form has these fields:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/setPrice" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"meter": "<meter>",
"price": {}
}'iam.api.billing.setPrice(
credential: CredentialInput,
input: {
tenantId: string;
meter: string;
targetTenantId?: string;
effectiveFrom?: string;
price: Record<string, unknown> | null;
note?: string;
},
): Promise<PriceView | null>setProfile
Creates or updates a billing profile: company, billing emails, tax ID, address, purchase order, cost center, payment terms.
- Permission:
iam:billing:manageoniam/billing/profile; a new profile below an organization is created from an ancestor withtargetTenantId. - Audited as:
billing:profile. - Errors:
ACCESS_DENIED(403) when a tenant below an organization creates its own;INVALID_INPUTon the root tenant or for more than 10 emails.
A profile below an organization makes that tenant a billing account of its own, a decision for its parent; afterwards
the tenant's own billing managers may keep it up to date. null clears a field.
Prop
Type
A ProfileView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/setProfile" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.setProfile(
credential: CredentialInput,
input: {
tenantId: string;
targetTenantId?: string;
companyName?: string | null;
billingEmails?: string[];
taxId?: string | null;
address?: string | null;
purchaseOrder?: string | null;
costCenter?: string | null;
paymentTermsDays?: number | null;
},
): Promise<ProfileView>setTerms
Sets a billing account's contract terms: a discount off the subtotal, a minimum monthly commitment, and the tax invoices add.
- Permission: Root administrators only (
iam:billing:manageoniam/billing/terms), called on the account. - Audited as:
billing:terms. - Errors:
INVALID_INPUTwhen the tenant is not a billing account, for a percentage outside 0 to 100, or a negative commitment.
Invoices issued from then on take the subtotal of their lines, subtract discountPercent, add the shortfall below
minimumCommitment (currency units per month, monthly invoices only) as a true-up, subtract coupons and credit, and
add taxRatePercent (labelled taxLabel, Tax by default) on the rest. null clears a term. Spend reports stay at
rate-card prices.
await iam.api.billing.setTerms(root, {
tenantId: acmeId,
discountPercent: 10,
minimumCommitment: 1000,
taxRatePercent: 20,
taxLabel: 'VAT',
});Prop
Type
A TermsView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/setTerms" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.setTerms(
credential: CredentialInput,
input: {
tenantId: string;
discountPercent?: number | null;
minimumCommitment?: number | null;
taxRatePercent?: number | null;
taxLabel?: string | null;
},
): Promise<TermsView>spend
Reports the spend of the tenant and every tenant below it for a month, grouped and filtered.
Used inBilling and spend
- Permission:
iam:billing:readoniam/billing. - Audited as:
iam:billing:read. - Errors:
NOT_FOUNDfor a team, department or sub-tenant outside the scope;INVALID_INPUTfor an unknowngroupByor a malformed month.
groupBy is meter (default), identity, agent, team, department, tenant, day or tag:{name}. Filters:
meter, identityId, teamId, departmentId, subTenantId, rollUp: false (no sub-teams or sub-departments) and
billableOnly (leave out chargeback meters). Each row has costMicros, amount, share (percent) and quantities
per meter; the current month carries a linear forecast. For showback, shareUnattributed: true (grouped by
identity, agent, team or department) spreads the unattributed row over the other groups by their share of
spend, reported as sharedMicros per row and for the report.
const report = await iam.api.billing.spend(admin, { tenantId, groupBy: 'team' });Prop
Type
A SpendReport object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/spend" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.spend(
credential: CredentialInput,
input: { tenantId: string; period?: string; groupBy?: SpendGroupBy } & SpendFilters,
): Promise<SpendReport>subscribe
Subscribes the billing account to a plan (id or key).
Used inBilling and spend
- Permission:
iam:billing:manageoniam/billing/subscriptions: self-serve plans for the account's billing managers, any plan for root administrators. - Audited as:
billing:subscription. - Errors:
ACCESS_DENIED(403) for a plan that is not self-serve, ortrialDaysfrom anyone but a root administrator;CONFLICT(409) when the account already subscribes to the plan;INVALID_TRANSITION(409) for an archived plan;INVALID_INPUTwhen the tenant is not a billing account.
seats defaults to 1. Outside a trial the rest of this month's advance fees and seats are invoiced at once (the
result's invoice, billingReason: 'subscription'); after that each monthly invoice bills the month ahead. A trial
bills nothing until it ends; the part of the month after it is billed on that month's invoice.
const { subscription, invoice } = await iam.api.billing.subscribe(orgAdmin, {
tenantId: acmeId,
plan: 'team',
seats: 8,
});Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/subscribe" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"plan": "<plan>"
}'iam.api.billing.subscribe(
credential: CredentialInput,
input: { tenantId: string; plan: string; seats?: number; trialDays?: number },
): Promise<{ subscription: SubscriptionView; invoice?: StatementSummary }>teamSpend
Reports a team's spend, with the teams below it, grouped by identity by default.
- Permission: The team's maintainers (and those of teams above it), or
iam:billing:read. - Audited as:
iam:billing:read, withmetadata.viateam-maintainerorpermission. - Errors:
ACCESS_DENIED(403) for anyone else;NOT_FOUNDfor a team outside the tenant.
Prop
Type
A SpendReport object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/teamSpend" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"teamId": "<teamId>"
}'iam.api.billing.teamSpend(
credential: CredentialInput,
input: { tenantId: string; teamId: string; period?: string; groupBy?: SpendGroupBy },
): Promise<SpendReport>trend
Returns monthly totals for the last months months (1 to 24, default 6), with the filters of spend.
Used inBilling and spend
- Permission:
iam:billing:readoniam/billing. - Audited as:
iam:billing:read.
Prop
Type
A SpendTrend object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/trend" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>"
}'iam.api.billing.trend(
credential: CredentialInput,
input: { tenantId: string; months?: number } & SpendFilters,
): Promise<SpendTrend>updateBudget
Changes a budget's name, amount, period, meters, thresholds, alerts or enforcement; its subject stays.
- Permission:
iam:billing:manageoniam/billing/budgets. - Audited as:
billing:budget-update. - Errors:
CONFLICT(409) for a name another budget uses;NOT_FOUNDfor a budget of another tenant.
meters: null counts every meter again.
Prop
Type
A BillingBudgetView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/updateBudget" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"budgetId": "<budgetId>"
}'iam.api.billing.updateBudget(
credential: CredentialInput,
input: { tenantId: string; budgetId: string } & Partial<
Omit<BillingBudgetInput, 'subjectType' | 'subjectId' | 'meters'>
> & { meters?: string[] | null },
): Promise<BillingBudgetView>updateMeter
Renames a meter, changes its unit or description, or archives it.
- Permission:
iam:billing:manageoniam/billing/meters/{key}. - Audited as:
billing:meter-update. - Errors:
NOT_FOUNDwhen the tenant does not define the key;INVALID_INPUTwhen changingaggregationorpricing.
An archived meter refuses new usage (METER_ARCHIVED) and keeps its history; archived: false restores it.
Prop
Type
A MeterView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/updateMeter" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"key": "<key>"
}'iam.api.billing.updateMeter(
credential: CredentialInput,
input: {
tenantId: string;
key: string;
name?: string;
unit?: string;
description?: string | null;
archived?: boolean;
},
): Promise<MeterView>updatePlan
Changes a plan, by id or key: name, items, description, trial, self-serve, archived.
- Permission: Root administrators only (
iam:billing:manageoniam/billing/plans), called on the root tenant. - Audited as:
billing:plan-update. - Errors:
NOT_FOUNDfor an unknown plan;INVALID_INPUTas forcreatePlan.
null clears description or trialDays. An archived plan takes no new subscriptions. Changes apply to invoices
drawn up afterwards.
Prop
Type
A PlanView object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/updatePlan" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"plan": "<plan>"
}'iam.api.billing.updatePlan(
credential: CredentialInput,
input: {
tenantId: string;
plan: string;
name?: string;
items?: unknown[];
description?: string | null;
trialDays?: number | null;
selfServe?: boolean;
archived?: boolean;
},
): Promise<PlanView>updateSubscription
Changes a subscription's seats.
- Permission:
iam:billing:manageoniam/billing/subscriptions(self-serve plans), or a root administrator. - Audited as:
billing:subscription-update. - Errors:
INVALID_TRANSITION(409) for an ended subscription;INVALID_INPUTfor seats outside 0 to 1000000.
Seats billed in advance for this month are prorated as invoice items on the next invoice (invoiceItems): added seats
for the rest of the month, credit for removed ones. Arrears seats follow the seat history on their own.
Prop
Type
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/updateSubscription" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"subscriptionId": "<subscriptionId>",
"seats": 1
}'iam.api.billing.updateSubscription(
credential: CredentialInput,
input: { tenantId: string; subscriptionId: string; seats: number },
): Promise<{ subscription: SubscriptionView; invoiceItems: InvoiceItemView[] }>voidStatement
Voids a finalized statement: its credit, invoice items, coupons and advance-billed months come back and the month reopens.
- Permission: Root administrators only (
iam:billing:manageoniam/billing/statements), called on the account or the root tenant. - Audited as:
billing:statement-void. - Errors:
INVALID_TRANSITION(409) for a statement already void, a draft, or one with payments or credit notes (issue a credit note instead).
Fix the usage, then close the month again: the new statement gets a new number. Credit the invoice created from a negative balance is revoked.
Prop
Type
A StatementSummary object:
Prop
Type
Example HTTP request
Only the required fields are shown; replace each <placeholder>. The response is { "data": … } on success or { "error": { "code", "message" } }.
curl -X POST "$IAM_URL/api/iam/billing/voidStatement" \
-H "Authorization: Bearer $BETTER_IAM_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Better-IAM: 1" \
-d '{
"tenantId": "<tenantId>",
"statementId": "<statementId>",
"reason": "<reason>"
}'iam.api.billing.voidStatement(
credential: CredentialInput,
input: { tenantId: string; statementId: string; reason: string },
): Promise<StatementSummary>Better IAM is created by Sean Filimon
Last updated