Skip to content
On this page

Developers › Get paid without a website

Products and prices

A catalogue: the things you sell, and what they cost.

Verified 6 November 2026Explain this to your team →

View as Markdown

A product is the thing. A price is an amount in a currency, attached to a product. They are separate because a product outlives any one amount — when you put your prices up, the old price is archived rather than edited, and anything already quoting it keeps quoting it.

Amounts are integers in minor units. The field is called unit_amount to match what you already know, but 6000 is $60.00, not sixty dollars. No decimal crosses this API in either direction.

Create a product and a price

bash
curl https://api.secureprocessing.app/v1/products \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{"name": "Blue Hole Two-Tank Dive"}'

curl https://api.secureprocessing.app/v1/prices \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
        "product": "prod_8kM2nP4qR6sT8uV0wX2yZ4aB",
        "currency": "usd",
        "unit_amount": 6000
      }'
ts
const product = await sp.products.create({ name: "Blue Hole Two-Tank Dive" });

const price = await sp.prices.create({
  product: product.id,
  currency: "usd",
  unit_amount: 6000, // minor units — $60.00
});

A price cannot be edited

Only active, nickname and metadata can be changed. The amount, the currency and the product are fixed for the life of the price, and an attempt to change one is refused rather than ignored.

The reason is that a price id is what gets stored elsewhere. If the amount behind an id could move, editing a typo would change what every link already in circulation charges — including one a customer has open right now — and there would be nothing in the record saying it had ever been anything else. To change what something costs, create a new price and archive the old one.

ts
const replacement = await sp.prices.create({
  product: product.id,
  currency: "usd",
  unit_amount: 6500,
});

await sp.prices.update(price.id, { active: false, nickname: "2026 rate" });

Let the payer choose the amount

For a donation, a deposit or a tip, give a range instead of a fixed amount. All three figures are minor units.

ts
await sp.prices.create({
  product: donation.id,
  currency: "bzd",
  custom_unit_amount: {
    minimum: 500,     // $5.00
    maximum: 100000,  // $1,000.00
    preset: 2500,     // what the field is filled in with
  },
});

A price has exactly one of unit_amount or custom_unit_amount. Neither is a price that charges nothing; both is a price with two answers to what it costs. Either is refused.

Reading them back

A product does not embed its prices. List them with the product filter, so a product with two hundred prices is a page you asked for rather than a response that surprises you.

bash
curl "https://api.secureprocessing.app/v1/prices?product=prod_8kM2nP4qR6sT8uV0wX2yZ4aB&active=true" \
  -H "Authorization: Bearer sk_test_..."

Archiving

Nothing here is ever deleted. active: false is the archive, and archiving a product deliberately leaves its prices alone — a payment made months ago has to stay readable, with the thing it was for still resolvable.

Events

EventWhen
product.createdA product was added.
product.updatedA product was edited or archived.
price.createdA price was created.
price.updatedA price was renamed, archived or re-tagged. Never repriced.