Skip to main content

Creating products and prices

This guide explains how to create products and prices, and how to manage them after creation.

Prerequisites

  • You have a valid Odus API secret key.
  • You understand the difference between products and prices. If not, read What are products and prices? first.

Creating a product

A product is the starting point. You must create a product before you can attach any prices to it.

Via the Dashboard: Go to Products → Products and click Add. Fill in the name and, optionally, a description and statement descriptor.

Via the API: Send a POST /products request:

{
"name": "Pro Plan",
"description": "Full access to all Pro features",
"statementDescriptor": "MYAPP PRO PLAN"
}

See the POST /products reference for the full parameter list.

The response includes the product id. You will need this ID when creating prices.

Fulfillment settings

A product also carries what Order Management System needs to ship it: Shippable (the product takes part in Order Management) and SKU (what the warehouse ships it under — a shippable product without one stays on its orders but never ships). Category is unrelated to fulfillment: it is sent as metadata to payment service providers, for example for VAT reporting.

See What the SKU decides for what each setting changes on the resulting order.

Attaching a recurring price

A recurring price charges the customer on a repeating schedule. You define the schedule using a billingSchedule with one or more cycle definitions.

Via the Dashboard: Go to Products → Prices and click Add. Select the product, choose Recurring as the type, select the currencies, and set the interval and amount for each currency.

Via the API: Send a POST /prices request:

{
"name": "Pro Plan — Monthly",
"type": "recurring",
"currency": "usd",
"product": "prod_2QGNGy637hJ9MnD5cK7thAjSvPV",
"billingSchedule": {
"cycleDefinitions": [
{
"position": 1,
"amount": 2999,
"intervalUnit": "month",
"intervalValue": 1
}
]
}
}

See the POST /prices reference for the full parameter list. The key fields are name, type (recurring), currency, product, and the billingSchedule.cycleDefinitions array. You can also include an optional amount as a one-time setup fee.

Each cycle definition specifies a position (order in the schedule), amount (charge in smallest currency unit), intervalUnit (minute, hour, day, week, month, or year), and intervalValue (number of intervals between charges).

tip

To offer the same plan in multiple currencies at once, use the Dashboard form. It lets you define amounts for several currencies in a single step, creating one price object per currency.

Attaching a one-time price

A one-time price charges the customer a fixed amount exactly once.

Via the Dashboard: Go to Products → Prices, click Add, and select One-time as the type.

Via the API: Send a POST /prices request with type: "one_time" and an amount:

{
"name": "Lifetime Access",
"type": "one_time",
"currency": "usd",
"amount": 29900,
"product": "prod_2QGNGy637hJ9MnD5cK7thAjSvPV"
}

One-time prices do not require a billingSchedule.

Selling a bundle of units

If a price represents several units of the same thing — a pack of four sessions, a case of twelve bottles — set quantity on the price. The amount still covers the whole pack, and Odus splits it into a per-unit amount when the price is used:

{
"name": "Session Pack",
"type": "one_time",
"currency": "usd",
"amount": 14796,
"quantity": 4,
"product": "prod_2QGNGy637hJ9MnD5cK7thAjSvPV"
}

A payment referencing this price produces a line item of quantity 4 at 3699 each, so wallets and gateway order sheets show 4x Session Pack — $36.99 instead of 1x Session Pack — $147.96. The customer is charged the same 147.96 either way.

quantity defaults to 1, so existing prices are unaffected. Two further rules apply:

  • The price amount (and the trial amount of a recurring price) must divide evenly by quantity, so each unit has a whole per-unit amount.
  • A quantity sent on the line item multiplies the price quantity. Ordering quantity: 2 of the pack above yields 8 units, charged 295.92.

Giving an item away for free

A price can have an amount of 0. That is how you sell a free item alongside a paid one — a gift with purchase, a bundled sample, a no-cost add-on — instead of discounting the paid product and losing the extra from the order.

{
"name": "Free Shaker Bottle",
"type": "one_time",
"currency": "usd",
"amount": 0,
"product": "prod_2QGNGy637hJ9MnD5cK7thAjSvPV"
}

Put the free price in the same cart as the paid one. The customer is charged the paid total, and both items appear on the payment, on the gateway's order sheet, and in Order Management, so the freebie is picked, packed and shipped like anything else.

A recurring price of 0 becomes an ordinary subscription that renews at no cost: every cycle produces a paid invoice and a succeeded payment, and the order is created as usual — the customer's card is simply never charged. Nothing zero-valued is ever sent to a payment provider.

note

Make a recurring item free by setting the price amount to 0, not by overriding the amount on a line item. A subscription bills from its price, so a line-item override applies to the first charge only and the item would renew at full price. Odus rejects that override rather than let it happen.

Editing a price

You can update a price's name, active status, quantity, billing schedule, and metadata after creation.

Via the Dashboard: Open the price from Products → Prices and edit the fields directly.

Via the API: Send a POST /prices/{id} request with the fields you want to change:

{
"name": "Pro Plan — Monthly (Updated)"
}
note

The currency of a price cannot be changed after creation. If you need a price in a different currency, create a new price.

Deleting a price

Via the Dashboard: Open the price from Products → Prices, click the actions menu, and select Delete.

Via the API: Send a POST /prices/{id}/delete request. No request body is required.

warning

A price cannot be deleted if it has already been used to make a payment. If you no longer want customers to use a price, set active to false instead. Inactive prices are hidden in the Dashboard but remain accessible via the API.