The Offering object
This object is an offering. Its type defaults to PRODUCT, but the same object also represents services, subscriptions, and contracts — see Offerings & types. The following fields are accepted on write and returned on read.
| Field | Type | Notes |
|---|---|---|
id | string | CUID, assigned on create (read-only) |
name | string (required) | Max 200 characters |
type | enum | PRODUCT (default) · SERVICE · SUBSCRIPTION · CONTRACT |
sku | string | Max 100 chars — catalog identity and primary upsert key |
category | string | null | By name; created automatically if new (max 100 chars). Returns null when no category is set. |
price | number | Nonnegative; defaults to 0 if omitted on create |
cost | number | null | Nonnegative; enables margin display (price − cost) |
currency | string | ISO 4217 code; defaults to USD |
unit | string | e.g. each, GB, hour (max 40 chars) |
billingPeriod | enum | null | MONTHLY · YEARLY (for subscriptions) |
termMonths | integer | null | Contract or subscription term in months (positive integer) |
stockQty | integer | null | Optional inventory count (min 0) |
reorderLevel | integer | null | Optional inventory reorder threshold (min 0) |
description | string | Max 10,000 characters |
features | string | Max 10,000 characters |
active | boolean | Defaults to true |
externalId | string | Your system's ID — secondary upsert key and dedupe handle (max 200 chars) |
createdAt | string (ISO 8601) | Assigned on create (read-only) |
updatedAt | string (ISO 8601) | Updated on every write (read-only) |
Example object
{
"id": "cmq1abc2def3ghi4jkl5",
"name": "4G Router",
"type": "PRODUCT",
"sku": "RTR-4G",
"price": 199,
"cost": 120,
"currency": "USD",
"unit": "each",
"billingPeriod": null,
"termMonths": null,
"stockQty": 50,
"reorderLevel": null,
"description": null,
"features": null,
"active": true,
"externalId": null,
"category": "Electronics",
"createdAt": "2025-06-01T12:00:00.000Z",
"updatedAt": "2025-06-01T12:00:00.000Z"
}Notes on specific fields
name is the only required field. All other fields are optional on write.
price defaults to 0 when omitted on create. On update, only fields explicitly included in the request body are changed.
category is sent and returned as a string name. The server resolves it to an internal category record, creating the category automatically if it does not exist yet.
sku and externalId are the two upsert keys. Lookup order: sku first, then externalId (if sku is absent from the row). If neither matches an existing product, a new one is created.