---
title: "Prices"
description: "Set how much a Product costs, and find prices by lookup key or search."
url: https://docs.fluveo.com/catalog/prices/
---

> Index of every page: https://docs.fluveo.com/llms.txt. Integrating Fluveo? Read https://docs.fluveo.com/agents/integrate.md first.

> Too long? This page with code in one language only: https://docs.fluveo.com/catalog/prices.curl.md (cURL), https://docs.fluveo.com/catalog/prices.node.md (Node.js), https://docs.fluveo.com/catalog/prices.python.md (Python), https://docs.fluveo.com/catalog/prices.php.md (PHP).

# Prices

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

A Price says how much a [Product](https://docs.fluveo.com/catalog/products.md) 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](https://docs.fluveo.com/api/prices.md).

## 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:

```bash
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
```

Node.js:

```javascript
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](https://docs.fluveo.com/catalog/products.md#create).

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](https://docs.fluveo.com/start/metadata.md)).

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:

```bash
curl -G https://api.fluveo.com/v1/prices \
  -H "Authorization: Bearer sk_test_..." \
  -d "lookup_keys[]=pro_tee"
```

Node.js:

```javascript
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](https://docs.fluveo.com/catalog/products.md#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](https://docs.fluveo.com/start/pagination.md)). Filter with `active`, `currency`,
`product`, `type`, `lookup_keys[]` (at most 10) and `created`.
`expand[]=data.product` returns each Price with its Product.

## Search prices

`GET /v1/prices/search` works like [Product search](https://docs.fluveo.com/catalog/products.md#search). The fields are `active`,
`currency`, `lookup_key`, `metadata`, `product` and `type`. `created` is not a
search field.

| Query | Finds |
| --- | --- |
| `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](https://docs.fluveo.com/webhooks/events.md).

> **For AI agents:**
>
> A Price's unit_amount, currency and product never change: add another Price, then archive the first.
> Move a lookup_key with transfer_lookup_key=true on the new Price, never by clearing it first.
> Fluveo refuses tiered prices and currency_options by name.
