Price formulas let you define dynamic pricing using mathematical expressions that are evaluated at billing time. This is useful for pricing models that depend on runtime variables - usage volume, contract size, exchange rates, or custom metrics.
Formulas support standard arithmetic operators, conditional logic, and named variables. Each variable has a type and optional default value. At billing time, the formula engine resolves all variables and computes the final price.
Example: base_price * (1 - volume_discount) where volume_discount increases with usage.
List formula inputs
Deprecated: use GET /price-formulas/inputs instead. Removed on 2026-11-30.
Lists the inputs the formula engine binds — quantity, tier_quantity, key, cost.
Required scope: price.read (Read prices).
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
List formula inputs › Responses
OK
List price formulas
Lists price formulas with cursor-based pagination.
Required scope: price.read (Read prices).
query Parameters
includeExtra data to add to the response: scheduled_versions. Send a comma-separated list or repeat the parameter. An unknown name is refused with 400. scheduled_versions is sent without being asked until 2026-11-30; after that date it is sent only when named here.
limitPage size. Values above the server-side cap are clamped (standard default 50, cap 200; a few document-heavy lists use larger windows). Invalid values fall back to the default.
cursorOpaque continuation token from the previous response's pagination.cursor. Omit for the first page. Cursors are stateless and do not expire, but are only valid for the list and filters that produced them.
has_scheduled_versionFilter by whether the entity has a version scheduled to publish (true or false). A scheduled version is a FROZEN version row a pending catalog.publish_version Change is bound to; the entity itself stays draft, published or archived and its working draft stays free for immediate changes.
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
List price formulas › Responses
OK
Create a price formula
Creates a price formula with a validated expression. The formula starts as a draft: a price can use it once its first version is published.
Required scope: price.write (Write prices).
query Parameters
includeExtra data to add to the response: scheduled_versions. Send a comma-separated list or repeat the parameter. An unknown name is refused with 400. scheduled_versions is sent without being asked until 2026-11-30; after that date it is sent only when named here.
Headers
Idempotency-KeyUnique key that makes this POST safe to retry: repeats with the same key replay the first response instead of re-executing. Replays are scoped to the retrying principal (same API key / user) and kept for 24 hours. Required on every POST.
Client-generated idempotency key (e.g. a UUID).
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Create a price formula › Request Body
expressionThe expression to evaluate for a tier rate; may reference declared variables, cost.
nameDisplay name for the formula.
Variables the expression references, each with a name, type, and optional default.
Create a price formula › Responses
Created
List formula inputs
Lists the inputs the formula engine binds — quantity, tier_quantity, key, cost.
Required scope: price.read (Read prices).
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
List formula inputs › Responses
OK
Preview a price formula
Evaluates a formula with variable bindings and changes nothing. Send either an inline expression or the id of a stored formula (its declared defaults apply under the bindings you send). Rate-table lookups read the rates in force now. Pass debug=true for a step-by-step trace.
Required scope: price.read (Read prices).
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Preview a price formula › Request Body
debugWhen true, the response includes a step-by-step evaluation trace.
expressionAd-hoc expression to evaluate; either this or formula_id is required.
formula_idA stored formula to evaluate; either this or expression is required.
Variable bindings supplied to the evaluation, keyed by variable name: a number (or a decimal string) for a numeric variable, text for a string one.
Preview a price formula › Responses
OK
Get a price formula
Returns a single price formula (expression plus variable definitions) by ID.
Required scope: price.read (Read prices).
path Parameters
idPrice formula UUID
query Parameters
includeExtra data to add to the response: scheduled_versions. Send a comma-separated list or repeat the parameter. An unknown name is refused with 400. scheduled_versions is sent without being asked until 2026-11-30; after that date it is sent only when named here.
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Get a price formula › Responses
OK
Delete a price formula
Deletes a price formula and archives its versions. A built-in formula cannot be deleted (409). Publishing a product version whose price still names the deleted formula is refused.
Required scope: price.write (Write prices).
path Parameters
idPrice formula UUID
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Delete a price formula › Responses
No Content
Update a price formula
Updates a price formula. A new name applies at once. A new expression or new variables are validated and go into the formula's working draft; they price nothing until that draft is published. The answer shows the formula in force.
Required scope: price.write (Write prices).
path Parameters
idPrice formula UUID
query Parameters
includeExtra data to add to the response: scheduled_versions. Send a comma-separated list or repeat the parameter. An unknown name is refused with 400. scheduled_versions is sent without being asked until 2026-11-30; after that date it is sent only when named here.
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Update a price formula › Request Body
expressionNew expression; omit to leave unchanged.
nameNew display name; omit to leave unchanged.
Replacement variable declarations; omit to leave unchanged.
Update a price formula › Responses
OK
Get the open working draft
The entity's ONE working draft: its row id, the version it publishes as, when it was opened, the version it is authored on top of, and a counted summary of what is staged. data is null when nothing is staged — a state, not an error.
Required scope: price.read (Read prices).
path Parameters
idEntity UUID
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Get the open working draft › Responses
OK
Open the working draft on a chosen base
Opens the working draft if none is open, and records which version it is authored on top of: the live head (omit base_version_id) or one of the entity's scheduled versions. Re-basing an open draft keeps its edits — the delta is the author's intent and is never rewritten — and re-materialises them over the new base. A publish of a draft based on a scheduled version cannot be scheduled to fire before that version does.
Required scope: price.write (Write prices).
path Parameters
idEntity UUID
Headers
Idempotency-KeyUnique key that makes this POST safe to retry: repeats with the same key replay the first response instead of re-executing. Replays are scoped to the retrying principal (same API key / user) and kept for 24 hours. Required on every POST.
Client-generated idempotency key (e.g. a UUID).
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Open the working draft on a chosen base › Request Body
base_version_idThe version the working draft is authored on top of — the live head, or one of the entity's scheduled versions. Omit for the head.
Open the working draft on a chosen base › Responses
OK
Discard the open working draft
Archives the working draft with reason 'discarded'. The live entity is untouched: nothing pointed at the draft and it was never on the billing timeline. 404 when nothing is staged, which is a different answer from a successful discard and is reported as one.
Required scope: price.write (Write prices).
path Parameters
idEntity UUID
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Discard the open working draft › Responses
No Content
Replace what the working draft contains
States what the draft should CONTAIN; the server derives the change against the draft's base and validates the result. A child the body omits is removed from the draft. Opens the working draft on the head when none is open.
Required scope: price.write (Write prices).
path Parameters
idEntity UUID
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Replace what the working draft contains › Request Body
expressionThe expression this version should evaluate.
The variables this version should declare, in the order they should be shown.
Replace what the working draft contains › Responses
OK
List a price-formula's version timeline
The entity's versions in the order they fired and will fire: history, head, scheduled releases, working draft. Published and scheduled rows are returned by default; pass include=all for the draft and the archived rows. Same row shape as /versions.
Required scope: price.read (Read prices).
path Parameters
idEntity UUID
query Parameters
includeSet to 'all' to include the working draft and archived rows.
limitPage size (default 100, max 200)
cursorOpaque continuation token from the previous response's pagination.cursor. Omit for the first page. Cursors are stateless and do not expire, but are only valid for the list and filters that produced them.
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
List a price-formula's version timeline › Responses
OK
List price-formula versions
Returns version rows for the entity, keyset-paginated (default 100, max 200 per page). The status filter accepts draft, scheduled, published, archived; the default excludes draft. include=usage_count adds how many records use each version; sort=version:desc lists the newest first.
Required scope: price.read (Read prices).
path Parameters
idEntity UUID
query Parameters
includeExtra data to add to the response: usage_count. Send a comma-separated list or repeat the parameter. An unknown name is refused with 400.
statusLifecycle status filter (repeatable / comma-separated): draft, scheduled, published, archived. Default excludes draft.
archived_reasonNarrow archived rows by reason (repeatable / comma-separated): canceled, discarded, errored, superseded
sortOrder: version:asc (the default) lists the versions in the order they fired and will fire; version:desc lists the highest number first, versions without a number (the working draft, archived rows) last.
limitPage size (default 100, max 200)
cursorOpaque continuation token from the previous response's pagination.cursor. Omit for the first page. Cursors are stateless and do not expire, but are only valid for the list and filters that produced them.
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
List price-formula versions › Responses
OK
Get a price-formula version snapshot
The version's own fields plus the common version header. {version} is the number, or the word 'draft' for the open working draft.
Required scope: price.read (Read prices).
path Parameters
idEntity UUID
versionThe version number, or the word 'draft' for the open working draft.
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Get a price-formula version snapshot › Responses
OK
Name or annotate a price-formula version
Sets the version's release_name and/or release_note. These are display metadata, not content: editing them never creates a new version and is allowed on published versions. An absent field is left unchanged; null clears it; an empty string is refused. It answers the version row without the data envelope; from 2026-11-30 it answers {"data": …} like every other operation.
Required scope: price.write (Write prices).
path Parameters
idEntity UUID
versionThe version number, or the word 'draft'.
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Name or annotate a price-formula version › Request Body
release_nameNew name; null clears it. Absent leaves it unchanged.
release_noteNew note; null clears it. Absent leaves it unchanged.
Name or annotate a price-formula version › Responses
OK
created_atWhen the row was opened — for a draft when editing started, for a release when it was armed.
effective_fromeffective_toidThe catalog_versions row id. A client selecting a version writes this, never the number.
originWho made this version: manual (an operator published it), scheduled_release (a scheduled publish fired), cascade (republished automatically because something it depends on published).
published_atstatusThe row's own state: draft, scheduled, published or archived.
versionThe version's display number, or 0 for a row that is not on the chain (a working draft, an archived row).
archived_reasonWhy an archived row left the timeline: canceled, discarded or superseded.
For origin=cascade: what caused this version.
What the version does differently from the version it replaced; from is absent for the entity's first version. Sent only with include=diff (plans and products).
Who published the version — the same actor the audit trail names: an operator, an API key, or the system for a cascade. Absent on a version not yet published and on one published before publishers were recorded.
rank1-based position in the entity's queue of scheduled versions — the order they will fire. Present only on scheduled rows.
recorded_atWhen the publish was captured, on the wall clock (its audit row). published_at is the operation's instant — a sandbox's test clock — and effective_from when it governs. Sent with include=diff on published versions that have an audit row.
release_nameOperator-given name of this version, shown beside its number.
release_noteFree-text note about this version.
scheduled_change_idThe pending catalog.publish_version Change that will publish this version — reschedule or cancel it there.
scheduled_forWhen this scheduled version is due to publish. Present only on a scheduled row.
usage_countPresent only with ?include=usage_count.
Compare two price-formula versions
Every cell that differs between two versions, with the value on each side. ?against= takes 'head' (the default), another version number, or 'draft'. The comparison is of the two versions' STORED grids — nothing is recomputed at read time.
Required scope: price.read (Read prices).
path Parameters
idEntity UUID
versionThe version number, or the word 'draft'.
query Parameters
againstWhat to compare against: 'head' (the default) for the live version, or another version number, or 'draft'.
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Compare two price-formula versions › Responses
OK
Preview what else publishing this version would publish
The entities that will publish BECAUSE this one does — a plan that tracks this product's latest, say — each with the cells its next head would carry that its current one does not. Derived on every read and never frozen: something that starts following tomorrow appears tomorrow.
Required scope: price.read (Read prices).
path Parameters
idEntity UUID
versionThe version number, or the word 'draft' for the open working draft.
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Preview what else publishing this version would publish › Responses
OK
Forecast the impact of superseding this price-formula version
Who is using the version in force today, and what a publish over it would move. pinnable reports whether holding a version is possible for this entity at all — it is false for tax rules, which are dated rather than pinned, so a caller must not render a pinned count for them. republishes_consumers is the cross-entity fan-out (publishing a price formula republishes every ACTIVE product whose head tiers reference it), and live_readers counts consumers billing off the live head, who move as soon as the publish lands. Read-only, and uncached: this is read at the moment money changes.
Required scope: price.read (Read prices).
path Parameters
idEntity UUID
versionVersion number (positive integer)
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Forecast the impact of superseding this price-formula version › Responses
OK
List price-formula version referrers
Offset-paginated drill-down of the referrers of one type for one version of the entity.
Required scope: price.read (Read prices).
path Parameters
idEntity UUID
versionVersion number (positive integer)
query Parameters
typeReferrer type to list (required)
limitPage size (default 50, max 200)
cursorOpaque continuation token from the previous response's pagination.cursor. Omit for the first page. Cursors are stateless and do not expire, but are only valid for the list and filters that produced them.
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
List price-formula version referrers › Responses
OK
Get price-formula version usage summary
Referrer counts for one version of the entity, grouped by referrer type. Powers the version-switcher hover card.
Required scope: price.read (Read prices).
path Parameters
idEntity UUID
versionVersion number (positive integer)
Headers
X-Workspace-IdSelects the workspace this request operates in, by workspace UUID or slug (e.g. a sandbox workspace for test integrations). Omitted: the organization's default live workspace. Unknown workspace: 404; workspace outside your organization: 403. Discover workspaces via GET /workspaces.
Workspace UUID or slug.
Get price-formula version usage summary › Responses
OK