A Price is what a Product costs: an amount in one currency, paid once (one_time). Create it for an existing product, or with product_data to make the product in the same call. Its amount, currency and product never change after creation: to change them, create a new price and archive the old one with active=false. A price is never deleted. Each change is also sent as a price.created or price.updated event (see Events); Fluveo never sends price.deleted. Tiered prices (tiers, tiers_mode) and currency_options are refused, so a price has one currency and one amount. The bounds of custom_unit_amount are 50 and 1,000,000 in the smallest currency unit (4,000,000 for brl), with minimum below maximum and preset between them. A lookup_key is unique within the store and mode; transfer_lookup_key=true takes it from the price that holds it in the same write, and that price gets its own price.updated. created is not a search field.
Send every request to https://api.fluveo.com/v1 with your secret key as a Bearer token. This page lists only what Fluveo serves; the OpenAPI file holds the same operations.
An operation or a parameter marked Preview works, but it is not locked yet and may change: what Preview means.
Creates a pricePreview#
POST/v1/pricesrak_plan_write
Preview: this operation works, but it is not locked yet; it may change.
Send product or product_data, not both, and one of unit_amount, unit_amount_decimal or custom_unit_amount. product may name an archived product, never a deleted one or another store's.
Send a unique key, 1 to 255 characters, on every POST. A retry with the same key and the same body returns the first answer instead of acting twice (with Idempotent-Replayed: true); the same key with another body is refused. Keys are kept 7 days, except on POST /v1/checkout/sessions, POST /v1/checkout/sessions/{session} and POST /v1/webhook_endpoints, where a key holds 24 hours; webhook endpoint keys are also capped at the newest 32 per store and mode. Do not rely on a replay after that window. GET and DELETE ignore it.
Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.
One of:
2026-05-27.dahlia.
false creates the price archived. Default true.
Three-letter ISO code, such as usd or brl. Fluveo normalizes uppercase input.
Lets the buyer choose the amount: enabled=true (required), with optional minimum, maximum and preset in the smallest currency unit. minimum is at least 50 and below maximum, maximum at most 1,000,000 (4,000,000 for brl), and preset between minimum and maximum. Not with unit_amount or unit_amount_decimal.
Your own key for the price, up to 200 characters, unique among the store's prices in this mode. A key another price holds is refused unless transfer_lookup_key=true.
Up to 50 key-value pairs of your own, sent as metadata[key]=value: keys of 1 to 40 characters, values up to 500. Keys starting with fluveo_ are reserved. On an update, an empty value removes a key.
A name for the price that buyers do not see, up to 5,000 characters.
The id of the Product this price is for.
A new Product to create with this price, in the same write: name (required), with optional id, active, metadata, statement_descriptor, tax_code and unit_label, under the rules of POST /v1/products.
7 child fields
Whether the amount includes tax: inclusive, exclusive or unspecified. Once inclusive or exclusive, it cannot change.
One of:
exclusive,inclusive,unspecified.true takes lookup_key from the price that holds it, in the same write; that price's lookup_key becomes null and it gets a price.updated event.
Divides the quantity before the amount is applied: divide_by (at least 2) and round (up or down), both required.
The price in the currency's smallest unit (cents for USD, centavos for BRL), 0 or more.
The price in the smallest unit as a decimal string, up to 12 decimal places, such as 15.5. Send it or unit_amount, not both.
Use only the documented body parameters. Send a new Idempotency-Key with each new request, and the same key again only to retry that request.
Returns a price object.
curl https://api.fluveo.com/v1/prices \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: $(uuidgen)" \
--data-urlencode "currency=usd" \
--data-urlencode "product=prod_123" \
--data-urlencode "unit_amount=2000"const response = await fetch("https://api.fluveo.com/v1/prices", {
method: "POST",
headers: {
"Authorization": "Bearer sk_test_...",
"Idempotency-Key": crypto.randomUUID(),
},
body: new URLSearchParams([["currency","usd"],["product","prod_123"],["unit_amount","2000"]]),
});
console.log(await response.json());import uuid
import requests
response = requests.post(
"https://api.fluveo.com/v1/prices",
headers={"Authorization": "Bearer sk_test_...", "Idempotency-Key": str(uuid.uuid4())},
data=[("currency", "usd"), ("product", "prod_123"), ("unit_amount", "2000")],
)
print(response.json())<?php
$ch = curl_init("https://api.fluveo.com/v1/prices");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer sk_test_...",
"Idempotency-Key: " . bin2hex(random_bytes(16)),
],
CURLOPT_POSTFIELDS => "currency=usd&product=prod_123&unit_amount=2000",
]);
echo curl_exec($ch);{
"active": true,
"created": 1767225600,
"currency": "usd",
"id": "price_123",
"livemode": false,
"metadata": {},
"object": "price",
"product": "prod_123",
"tax_behavior": "unspecified",
"type": "one_time",
"unit_amount": 2000,
"unit_amount_decimal": "2000"
}Lists price objects, newest firstPreview#
GET/v1/pricesrak_plan_read
Preview: this operation works, but it is not locked yet; it may change.
Only active prices (true) or only archived ones (false).
Filter on the creation time, a Unix timestamp: created=<t> for an exact match, or created[gt], created[gte], created[lt], created[lte].
Only prices in this currency.
Cursor: the id of the first object of the current page, to get the previous page. Do not send it with starting_after.
How many objects to return, from 1 to 100. Default 10.
Only the prices with these lookup keys, sent as lookup_keys[]=..., at most 10.
Only the prices of this Product. An unknown product answers resource_missing.
Cursor: the id of the last object of the previous page, to get the next page. Do not send it with ending_before.
Only prices of this type.
One of:
one_time.
Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.
One of:
2026-05-27.dahlia.
Returns a list of price objects.
curl -G https://api.fluveo.com/v1/prices \
-H "Authorization: Bearer sk_test_..." \
--data-urlencode "active=true" \
--data-urlencode "product=prod_123"const response = await fetch("https://api.fluveo.com/v1/prices" + "?" + new URLSearchParams([["active","true"],["product","prod_123"]]), {
method: "GET",
headers: {
"Authorization": "Bearer sk_test_...",
},
});
console.log(await response.json());import requests
response = requests.get(
"https://api.fluveo.com/v1/prices",
headers={"Authorization": "Bearer sk_test_..."},
params=[("active", "true"), ("product", "prod_123")],
)
print(response.json())<?php
$ch = curl_init("https://api.fluveo.com/v1/prices?active=true&product=prod_123");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer sk_test_...",
],
]);
echo curl_exec($ch);{
"data": [
{
"active": true,
"created": 1767225600,
"currency": "usd",
"id": "price_123",
"livemode": false,
"metadata": {},
"object": "price",
"product": "prod_123",
"tax_behavior": "unspecified",
"type": "one_time",
"unit_amount": 2000,
"unit_amount_decimal": "2000"
}
],
"has_more": false,
"object": "list",
"url": "/v1/prices"
}Updates a pricePreview#
POST/v1/prices/{price}rak_plan_write
Preview: this operation works, but it is not locked yet; it may change.
Only active, nickname, lookup_key, transfer_lookup_key, tax_behavior and metadata change; unit_amount, currency and product answer parameter_unknown. The price a product names as its default_price cannot be archived.
The Price's id.
Send a unique key, 1 to 255 characters, on every POST. A retry with the same key and the same body returns the first answer instead of acting twice (with Idempotent-Replayed: true); the same key with another body is refused. Keys are kept 7 days, except on POST /v1/checkout/sessions, POST /v1/checkout/sessions/{session} and POST /v1/webhook_endpoints, where a key holds 24 hours; webhook endpoint keys are also capped at the newest 32 per store and mode. Do not rely on a replay after that window. GET and DELETE ignore it.
Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.
One of:
2026-05-27.dahlia.
false archives the price; true makes it active again. The price a product names as its default_price cannot be archived.
Your own key for the price, up to 200 characters, unique among the store's prices in this mode. A key another price holds is refused unless transfer_lookup_key=true.
Up to 50 key-value pairs of your own, sent as metadata[key]=value: keys of 1 to 40 characters, values up to 500. Keys starting with fluveo_ are reserved. On an update, an empty value removes a key.
A name for the price that buyers do not see, up to 5,000 characters.
Whether the amount includes tax: inclusive, exclusive or unspecified. Once inclusive or exclusive, it cannot change.
One of:
exclusive,inclusive,unspecified.true takes lookup_key from the price that holds it, in the same write; that price's lookup_key becomes null and it gets a price.updated event.
Use only the documented body parameters. Send a new Idempotency-Key with each new request, and the same key again only to retry that request.
Returns a price object.
curl https://api.fluveo.com/v1/prices/price_123 \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: $(uuidgen)" \
--data-urlencode "nickname=Launch price"const response = await fetch("https://api.fluveo.com/v1/prices/price_123", {
method: "POST",
headers: {
"Authorization": "Bearer sk_test_...",
"Idempotency-Key": crypto.randomUUID(),
},
body: new URLSearchParams([["nickname","Launch price"]]),
});
console.log(await response.json());import uuid
import requests
response = requests.post(
"https://api.fluveo.com/v1/prices/price_123",
headers={"Authorization": "Bearer sk_test_...", "Idempotency-Key": str(uuid.uuid4())},
data=[("nickname", "Launch price")],
)
print(response.json())<?php
$ch = curl_init("https://api.fluveo.com/v1/prices/price_123");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer sk_test_...",
"Idempotency-Key: " . bin2hex(random_bytes(16)),
],
CURLOPT_POSTFIELDS => "nickname=Launch%20price",
]);
echo curl_exec($ch);{
"active": true,
"created": 1767225600,
"currency": "usd",
"id": "price_123",
"livemode": false,
"metadata": {},
"object": "price",
"product": "prod_123",
"tax_behavior": "unspecified",
"type": "one_time",
"unit_amount": 2000,
"unit_amount_decimal": "2000"
}Retrieves a pricePreview#
GET/v1/prices/{price}rak_plan_read
Preview: this operation works, but it is not locked yet; it may change.
The Price's id.
Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.
One of:
2026-05-27.dahlia.
Returns a price object.
curl https://api.fluveo.com/v1/prices/price_123 \
-H "Authorization: Bearer sk_test_..."const response = await fetch("https://api.fluveo.com/v1/prices/price_123", {
method: "GET",
headers: {
"Authorization": "Bearer sk_test_...",
},
});
console.log(await response.json());import requests
response = requests.get(
"https://api.fluveo.com/v1/prices/price_123",
headers={"Authorization": "Bearer sk_test_..."},
)
print(response.json())<?php
$ch = curl_init("https://api.fluveo.com/v1/prices/price_123");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer sk_test_...",
],
]);
echo curl_exec($ch);{
"active": true,
"created": 1767225600,
"currency": "usd",
"id": "price_123",
"livemode": false,
"metadata": {},
"object": "price",
"product": "prod_123",
"tax_behavior": "unspecified",
"type": "one_time",
"unit_amount": 2000,
"unit_amount_decimal": "2000"
}Searches price objects with a query, newest firstPreview#
GET/v1/prices/searchrak_plan_read
Preview: this operation works, but it is not locked yet; it may change.
A query is one or more clauses, each a field, an operator and a quoted value, such as product:"prod_123" or active:"true". The price fields are active, currency, lookup_key, product, type and metadata["key"]; created is not one. Every price field takes only the operator :. On lookup_key and product it matches a run of whole words in any case; on active (true or false), currency and type it matches the whole value. A - before a clause negates it. field:null matches a field that is absent or empty, and -field:null one that is set. Join clauses with AND or OR (a space means AND), never both in one query and never with parentheses, up to 10 clauses. Quote values with single or double quotes; a backslash keeps the next character as it is. A query Fluveo cannot read answers invalid_request_error with the reason and its column. When has_more is true, send next_page as page with the same query for the next page. Add expand[]=total_count to get total_count, the number of matches. A price is found as soon as its write returns.
How many objects to return, from 1 to 100. Default 10.
The next_page of the previous answer, to get the page after it. Send the same query with it.
The search query, in the language the description above gives.
Optional. The only version Fluveo serves is 2026-05-27.dahlia; any other value is refused with a 400. Every answer names that version in its own Fluveo-Version header, except the refusals Fluveo gives before it reads the request (no key, an unknown key, an unknown URL, a body that is not a form) and a file's bytes, which name no version and no Request-Id.
One of:
2026-05-27.dahlia.
Returns a list of price objects.
curl -G https://api.fluveo.com/v1/prices/search \
-H "Authorization: Bearer sk_test_..." \
--data-urlencode "query=product:\"prod_123\" AND active:\"true\""const response = await fetch("https://api.fluveo.com/v1/prices/search" + "?" + new URLSearchParams([["query","product:\"prod_123\" AND active:\"true\""]]), {
method: "GET",
headers: {
"Authorization": "Bearer sk_test_...",
},
});
console.log(await response.json());import requests
response = requests.get(
"https://api.fluveo.com/v1/prices/search",
headers={"Authorization": "Bearer sk_test_..."},
params=[("query", "product:\"prod_123\" AND active:\"true\"")],
)
print(response.json())<?php
$ch = curl_init("https://api.fluveo.com/v1/prices/search?query=product%3A%22prod_123%22%20AND%20active%3A%22true%22");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer sk_test_...",
],
]);
echo curl_exec($ch);{
"data": [
{
"active": true,
"created": 1767225600,
"currency": "usd",
"id": "price_123",
"livemode": false,
"metadata": {},
"object": "price",
"product": "prod_123",
"tax_behavior": "unspecified",
"type": "one_time",
"unit_amount": 2000,
"unit_amount_decimal": "2000"
}
],
"has_more": false,
"next_page": null,
"object": "search_result",
"url": "/v1/prices/search"
}