Costs
A cost records what something costs you, so a formula can
price from it. It is the difference between typing 115.00 into a tier and
saying cost.ek * 1.15 and letting the number follow reality.
Costs are also what makes margin reporting possible: revenue is only half of a margin.
Two scopes
Every cost is one or the other, and GET /v1/costs filters by exactly this
(scope=ORG or scope=PRODUCT).
Org-scoped
An upstream fee that is the same wherever it appears: a payment provider's percentage, a carrier rate, a licence you pay per user across the whole catalog. Defined once, referenced by any formula, changed in one place.
Create it with POST /v1/costs and it is org-scoped.
Product-scoped
A cost that belongs to one product, because it only means something there.
Shipping for a physical item, or the wholesale rate for one specific SKU. Create
it with POST /v1/products/{id}/costs and the cost is owned by that product: the
URL decides the scope. Like a price, a product cost is staged on the product's
working draft and reaches billing when the product is next published.
A product can carry several named costs, which is why they are keyed rather than being a single "cost" field.
Code
Static or calculated
A cost holds exactly one of a fixed amount or an expression.
| Kind | Field | Example |
|---|---|---|
| Static | amount | 45.00 CHF |
| Calculated | expression | { "source": "cost.primary + cost.shipping", "currency": "CHF" } |
An expression references other costs as cost.<key>, and must evaluate in the
currency it names, the same currency as every cost it reads. A composite cost
stays correct
when one of its parts changes. Change shipping and every cost built on it
follows, and so does every price whose formula reads it.
Check who depends on a cost before changing it
A cost is a shared input. GET /v1/costs/{id}/consumers lists the products that
consume it (for an org-scoped cost, every active product whose live version
carries its key), which is the thing to look at before re-negotiating a
number that forty tiers are priced from.
Create one in the dashboard
Over the API, this is POST /v1/costs, or POST /v1/products/{id}/costs for a
product-scoped cost; see Create one with the API.
-
Open the catalog
Pricing Catalog, then the Costs tab. The Org-scoped / Product-scoped / All filter is the fastest way to see which is which.
-
Add the cost
Give it a key, which is the name formulas will use, and either a value or an expression. Write a description; six months later
primarywill not be self-explanatory. -
Price from it
In a formula, reference the key:
cost.primary * 1.15, orcost.primary + cost.shippingfor a composite.
Create one with the API
Only key is required, and you must set exactly one of amount or
expression. Sending both, or neither, is rejected.
DELETE /v1/costs/{id} removes a cost. A product-scoped cost leaves billing at
the product's next publish; until then PATCH /v1/costs/{id} with
{"status": "active"} takes the removal back. An org-scoped cost is retired
directly.
Dashboard and API names
| In the dashboard | In the API |
|---|---|
| Cost Key | key, what formulas reference |
| PRODUCT column | product_id on the cost; null for an org-scoped cost |
| Org-scoped / Product-scoped filter | scope: "ORG" or "PRODUCT" |
| Value | amount, a Money value { "value", "currency" } |
| a calculated cost | expression: source referencing cost.<key>, plus currency |
| what depends on it | GET /costs/{id}/consumers |
Going deeper
| Topic | What it adds |
|---|---|
| Formulas | The expressions that read these values |
| Pricing models | How the resulting rates apply across tiers |
| Analytics | Margin, which needs cost as well as revenue |
Reference
| Topic | When you need it |
|---|---|
| Products | Product-scoped costs on the product itself |
| Costs API | Every field, plus consumers, remove and restore |