Docs
API 2026-05-27.dahlia Dashboard

Catalog

Set how much a Product costs, and find prices by lookup key or search.

A Price says how much a Product costs. A Product can have many Prices, for example one per currency. A Price never changes its amount or currency: to charge something else, add another Price and archive this one.

The API serves create, retrieve, update, list and search. A Price has no delete: you archive it. The full list of parameters is in the Prices API reference.

Amounts#

A Price is paid once, so its type is one_time. unit_amount is a whole number of the currency's smallest unit, so 4900 with usd means $49.00. When a Price must hold part of that unit, such as a tenth of a cent, send it as a decimal string in unit_amount_decimal instead, with no more than 12 digits after the point.

A price for an existing product
curl https://api.fluveo.com/v1/prices \
  -H "Authorization: Bearer sk_test_..." \
  -H "Idempotency-Key: 9b3e51a0-pro-tee" \
  -d product=prod_... \
  -d currency=usd \
  -d unit_amount=2900 \
  -d lookup_key=pro_tee
const response = await fetch("https://api.fluveo.com/v1/prices", {
  method: "POST",
  headers: { Authorization: "Bearer sk_test_...", "Idempotency-Key": "9b3e51a0-pro-tee" },
  body: new URLSearchParams({
    product: "prod_...",
    currency: "usd",
    unit_amount: "2900",
    lookup_key: "pro_tee",
  }),
});
const price = await response.json();

Name the Product with product, or create one in the same request with product_data[name]; send exactly one of the two. An archived Product still takes new Prices. To create a Product and its first Price together, see Create a product with its first price.

Other options:

  • nickname: free text, up to 5,000 characters, to tell your Prices apart. The dashboard calls it the price description.
  • custom_unit_amount[enabled]=true: the buyer chooses the amount, with an optional minimum, maximum and preset, in the smallest currency unit. minimum is at least 50 and below maximum; maximum is at most 1,000,000, or 4,000,000 in brl; preset is between them. Never together with unit_amount.
  • transform_quantity: divide_by and round (up or down), both required.
  • tax_behavior: inclusive when the amount already holds the tax, exclusive when tax goes on top, and unspecified until you decide. You can set it later on an unspecified Price, and from then on it stays.
  • metadata (see Metadata).

Fluveo refuses what it does not support, each by name and never silently: tiered prices and currency_options (a Price has one currency; create one Price per currency).

Lookup keys#

Store a short name such as pro_tee in lookup_key (200 characters at most), and your code can ask for the Price by that name rather than keep its price_... id. A key sits on one Price at a time in your store and mode. If another Price already has it, the request is refused and the error says which Price that is. Add transfer_lookup_key=true and the request takes the key over instead: the former holder drops it in the same write and sends a price.updated of its own.

Raising the Pro T-shirt from $29.00 to $32.00 takes three calls:

  1. Create the 3200 Price with lookup_key=pro_tee and transfer_lookup_key=true.
  2. If the old Price was the Product's default, point default_price at the new one.
  3. Archive the old Price with active=false.

From the first call on, a read of pro_tee answers the new amount.

Read the price that holds a key
curl -G https://api.fluveo.com/v1/prices \
  -H "Authorization: Bearer sk_test_..." \
  -d "lookup_keys[]=pro_tee"
const query = new URLSearchParams({ "lookup_keys[]": "pro_tee" });
const response = await fetch("https://api.fluveo.com/v1/prices?" + query, {
  headers: { Authorization: "Bearer sk_test_..." },
});
const { data } = await response.json();

Update and archive#

POST /v1/prices/{id} takes active, nickname, lookup_key, transfer_lookup_key, tax_behavior and metadata. unit_amount, currency and product are refused. An empty nickname= or lookup_key= sets it to null.

active=false archives a Price. It stays readable and active=true brings it back. The Product's default Price can't be archived: first make another Price the default with default_price on the Product update.

List prices#

GET /v1/prices returns your store's Prices, newest first, paged with limit (1 to 100, default 10), starting_after and ending_before (see Pagination). Filter with active, currency, product, type, lookup_keys[] (at most 10) and created. expand[]=data.product returns each Price with its Product.

GET /v1/prices/search works like Product search. The fields are active, currency, lookup_key, metadata, product and type. created is not a search field.

QueryFinds
product:"prod_..." AND active:"true"the active Prices of one Product
currency:"brl" AND active:"true"active Prices in reais
lookup_key:"pro_tee"the Price that holds this key
metadata["line"]:"pro"Prices whose line metadata is pro

Events#

A create sends price.created, and an update price.updated with previous_attributes. A Price is never deleted, so no price.deleted is sent. See Event types.