Skip to main content

What is a Price?

A Price defines how a product is billed. It can be a one-time payment or a recurring subscription with different billing frequencies.
Identifier format: price_ followed by 36 alphanumeric characters.Example: price_abc123def456ghi789jkl012mno345

Product → Price Relationship

A price is attached to a product through productId, and a product can carry several prices for different pricing strategies:
This flexibility lets you offer multiple payment options for the same product and support multiple currencies.

Price Attributes

Main Attributes

Recurring Attributes (Subscriptions)

Create a Price

A first price is posed at product creation with defaultPriceData (see Products). POST /v1/prices is the door for the second price — an annual tier next to the monthly one, or a second currency — by indicating in the body the product it attaches to.

Request Body

string
Identifier of the product this price attaches to. Either productId or skuId is required — neither is individually mandatory at the validator level, but the request is rejected if both are absent. skuId is a legacy form, kept for compatibility; productId remains the normal path.
number
required
Amount in the currency’s main unit. Strictly positive, up to 99999999.99.
string
required
Currency code, stored and returned lowercase. Required — there is no default currency. Limited to xaf and eur, see the Supported Currencies section further down.
enum
default:"one_time"
one_time or recurring.
enum
day, week, month, or year. Recurring prices only.
number
Number of intervals per billing cycle. Strictly positive.
number
Free trial days, 0 or more.
boolean
default:"true"
Pass false to create the price already deactivated.
A price is immutable. PUT /v1/prices/{id} only updates the active field — no other field is read, even if present in the body. To change an amount, currency, or billing cadence, create a new price: at matching dimensions (product × currency × type × cadence), the previously active price is automatically deactivated. Details of this replacement rule further down, in the API Response section.

Pricing Types

One-Time (one_time)

The customer pays once to access the product.Use cases:
  • One-off purchases
  • Physical products
  • Digital downloads
  • Lifetime access

Billing Intervals

For recurring prices, define the billing frequency:

Trial Periods

Offer a free trial period to attract new customers:
1

Subscription starts

The customer signs up and starts their free trial period
2

Trial period

For 14 days, the customer has full access without being billed
3

Trial ends

At the end of the trial, the first payment is automatically charged
4

Recurring cycle

Subsequent payments are charged according to the defined interval
Make sure to clearly inform your customers of the trial duration and the amount that will be billed afterward.

Multi-currency Management

Create one price per currency for the same product. Each price corresponds to a separate POST /v1/prices call:

Supported Currencies

The list is closed, not indicative. currency is validated against an enumeration — any other value, including a real ISO 4217 code like XOF or USD, is refused with 422. Only two currencies are accepted today.
All amounts are expressed in the currency’s main unit, never in cents. For example: 25000 XAF = 25,000 XAF, 39 EUR = €39.

API Response

GET /v1/prices/{id} exposes product and sku at the root of the object.
string
Identifier of the parent product.
object
The parent product, always present.
string | null
Inherited. null for a price created at the product level — the normal path today.
object | null
Inherited. The variant the price comes from, for prices created before the SKU left the creation contract. null otherwise.
price.sku can hold a non-null object. A price created through the legacy path (attached to a variant) still carries it, and will keep carrying it until it’s replaced by a new price. Any integration that dereferences price.sku — for example price.sku.product — must guard against null in both directions: don’t crash when it’s absent, and don’t assume it always is.
Replacement rule. Creating a price automatically deactivates the price that was active for the same product, the same currency, the same type and the same cadence (billingInterval + billingIntervalCount). This is what makes a price immutable: instead of editing an existing price, you create a new one, and the replacement happens on its own.A consequence worth knowing: a monthly price and an annual price share the same type (recurring) but a different cadence, so they coexist without replacing each other — this is how you offer both options on the same product.

Common Operations

Create a Price

Retrieve a Price

List a Product’s Prices

GET /v1/prices accepts the following filters, which can be combined:

Deactivate a Price

🛑 This page long claimed that “prices cannot be deleted if they are associated with active subscriptions” — that’s false, and not just nuanced: there is no condition at all. DELETE /v1/prices/{id} doesn’t delete anything and never checks any subscription — it unconditionally deactivates the price (active: false) and returns {"message": "Price deactivated"}. PUT produces the same effect, and it’s the only change it accepts.

Pricing Strategies

Monthly vs. Annual Pricing

Offer a discount for the annual subscription — two POST /v1/prices calls on the same product, with two different cadences:
9,000 XAF/month vs. 90,000 XAF/year works out to about 2 free months, which encourages customers to commit for the year.

Tiered Pricing

Create one product per service tier, each with its own price:

Useful Getters

The Price model provides getters to simplify checks:

Best Practices

Amounts are expressed in the currency’s main unit, never in cents:
  • XAF: 25000 = 25,000 XAF
  • EUR: 39 = €39
Decimals are accepted and the amount cannot exceed 99999999.99. The API returns it as a decimal string ("25000.00").
  • A price is immutable: never rely on PUT to change an amount, currency, or cadence — it only touches active
  • Create a new price; the previously active price of matching dimensions deactivates on its own
  • Read the product from price.product
  • Deactivate old prices rather than deleting them
  • Keep the number of active prices to the minimum necessary
  • Keep in mind that a new price deactivates the active price of the same product, currency, type, and cadence
  • 7 to 14 days is generally optimal
  • Too short: not enough time to evaluate
  • Too long: potential loss of revenue
  • Adjust prices for each market (not a straight conversion)
  • Account for local purchasing power
  • Use psychological pricing (9,000 XAF rather than 8,750 XAF)

Next Steps

Create Promotions

Apply discounts with coupons and promo codes

Manage Subscriptions

Understand the subscription lifecycle