Products are the line items inside a contract. Each product defines what is being charged, how it is scheduled, and what pricing model applies.
Base fields
| Field | Type | Required | Description |
|---|
displayName | string | Yes | Label shown on invoices |
scheduling | object | Yes | When and how often the product bills |
pricing | object | Yes | The pricing model |
catalogProductId | string | No | Links to a catalog product — required for all usage-based pricing |
description | string | No | Internal description |
paymentTerm | string | No | prepayment or postpayment — defaults based on pricing type |
isCalendarAligned | boolean | No | Align invoice periods to calendar months (default: false) |
commitment | object | No | Minimum committed units — see Commitment |
productErpId | string | No | ERP identifier for accounting sync |
Scheduling
{
"scheduling": {
"billingDay": 1,
"duration": { "unit": "MONTH", "value": 1 }
}
}
| Field | Type | Description |
|---|
billingDay | integer (1–31) | Day of month the billing period starts. Defaults to 1. Should match the contract start date to avoid proration. |
duration.unit | string | DAY, WEEK, MONTH, or YEAR |
duration.value | integer (0–1000) | Number of units per billing period |
Pricing models
ONE_TIME
A single charge billed when the contract starts. Duration must be 1 day.
{
"pricing": {
"type": "ONE_TIME",
"price": 500.00
}
}
SUBSCRIPTION
Recurring fixed fee. The subscriptionCadence controls how often the charge accumulates within the billing period.
{
"pricing": {
"type": "SUBSCRIPTION",
"price": 99.00,
"subscriptionCadence": { "unit": "MONTH", "value": 1 }
}
}
A product with a 3-month duration and monthly subscriptionCadence bills 3× 99=297 per invoice.
CONTRACT_TERMS
A total contract fee, optionally split into installments at specific dates.
{
"pricing": {
"type": "CONTRACT_TERMS",
"price": 12000.00,
"installments": [
{ "installmentDate": "2026-01-01T00:00:00Z", "amount": 6000.00 },
{ "installmentDate": "2026-07-01T00:00:00Z", "amount": 6000.00 }
]
}
}
PER_UNIT
Pay-as-you-go. Requires catalogProductId.
{
"pricing": {
"type": "PER_UNIT",
"price": 0.002,
"chunkSize": 1000,
"baseAmount": 500,
"usageReset": 1
}
}
| Field | Type | Description |
|---|
price | number | Price per unit (or per chunk if chunkSize is set) |
chunkSize | number | Billing granularity — usage is rounded up to the nearest chunk |
baseAmount | number | Free units included before metered charges begin |
usageReset | number | Reset accumulated usage every N months — must be 1, 2, 3, 6, or 12 |
TIERED
Volume-based pricing with different rates or flat fees per tier. Requires catalogProductId.
{
"pricing": {
"type": "TIERED",
"tiers": [
{ "fromInclusive": 0, "toExclusive": 1000, "rate": 0.10 },
{ "fromInclusive": 1000, "toExclusive": 10000, "rate": 0.07 },
{ "fromInclusive": 10000, "rate": 0.04 }
],
"subscriptionCadence": { "unit": "MONTH", "value": 1 },
"autoUpgrade": false,
"prorate": false,
"baseAmount": 0,
"usageReset": 1
}
}
| Tier field | Type | Description |
|---|
fromInclusive | number | Lower bound of the tier (inclusive) |
toExclusive | number | null | Upper bound (exclusive). Omit or null for the final open-ended tier |
rate | number | Per-unit rate in this tier |
flatFee | number | Flat fee charged when usage enters this tier |
packageSize | number | Units grouped into a package for billing |
| Tiered option | Type | Description |
|---|
subscriptionCadence | object | Makes tiered pricing subscription-based (charges flat fees on a cadence) |
autoUpgrade | boolean | Automatically move to the next tier in the following billing period |
prorate | boolean | Prorate flat fees based on when the tier was entered mid-period |
isRevShare | boolean | Revenue share mode — rate is treated as a percentage |
baseAmount | number | Free units before tiered charges apply |
usageReset | number | Reset usage every N months: 1, 2, 3, 6, or 12 |
Commitment
Attach a minimum committed usage to any usage-based product.
{
"commitment": {
"units": 10000,
"price": 500.00,
"overageStrategy": "IGNORE"
}
}
| Field | Type | Description |
|---|
units | number | Committed usage units |
price | number | Price charged for the committed amount |
overageStrategy | string | What happens when usage exceeds the commitment — IGNORE (default) |
scheduling | object | For recurring commitments — same shape as product scheduling |
Product groups
Products can be grouped to share ERP settings, commitments, and a combined line item on invoices.
{
"productGroups": [
{
"displayName": "Platform Bundle",
"products": [
{
"displayName": "Base Subscription",
"scheduling": { "billingDay": 1, "duration": { "unit": "MONTH", "value": 1 } },
"pricing": { "type": "SUBSCRIPTION", "price": 500.00, "subscriptionCadence": { "unit": "MONTH", "value": 1 } }
},
{
"displayName": "API Usage",
"scheduling": { "billingDay": 1, "duration": { "unit": "MONTH", "value": 1 } },
"pricing": { "type": "PER_UNIT", "price": 0.001, "chunkSize": 100 },
"catalogProductId": "cat_abc123"
}
]
}
]
}
Products inside a productGroup cannot use isCalendarAligned. Group-level settings like commitment and ERP fields apply to all products in the group.