Update a price
The prices.update operation: PATCH /api/v1/prices/{id} in the REST API and the prices_update tool in the MCP server.
/api/v1/prices/{id}Changes a price's nickname, lookup key, metadata or active (false archives it, true reactivates it). Send
only the fields to change; null clears an optional value; metadata replaces the whole map.
While no checkout session or payment has used the price (used: false), its tax behaviour and amounts can
change as well: each of amount, customAmount, creditPack and recurring replaces the stored value.
Once used, those are fixed (price_immutable): create a new price, move the lookup key to it with
prices.move_lookup_key, and archive this one. The type and currency never change.
A lookup key held by another price isn't moved silently (lookup_key_taken); use prices.move_lookup_key.
At a glance
- REST:
PATCH /api/v1/prices/{id} - MCP tool:
prices_update - Operation ID:
prices.update - Scope: Brand
- Permission:
catalog:write - Risk tier:
write - Dry run: Supported (send
Ownrecord-Dry-Run: true) - Idempotency:
Idempotency-Keyoptional - Modes: Test and live
- Authentication: API key with the
catalog:writescope - Since: M4
Request
Path parameters
| Field | Type | Description |
|---|---|---|
id | price_… ID |
Body
A JSON object (Content-Type: application/json):
| Field | Type | Required | Description |
|---|---|---|---|
nickname | string or null | No | |
lookupKey | string or null | No | Set a free lookup key, or null to remove it. To take one from another price, use prices.move_lookup_key. |
metadata | object | No | Your own key-value pairs (at most 50 keys). On updates the whole set is replaced. |
active | boolean | No | false archives the price, true reactivates it. |
taxBehavior | one of inclusive, exclusive | No | Unused prices only. |
amount | object or null | No | Unused prices only: the fixed amount; null removes it. |
customAmount | object or null | No | Unused prices only: the custom amount range; null removes it. |
creditPack | object | No | Unused credit packs only: the credit terms. |
creditPack.credits | object | No | The pack's nominal credits; equals the amount (the default). Custom-amount packs have none. What the wallet receives follows the brand's credit basis (net by default). |
creditPack.credits.amount | string | Yes | Integer micros as a string (12500000 = 12.50). |
creditPack.credits.currency | string | Yes | ISO 4217 currency code: the price's currency. |
creditPack.bonusCredits | object | No | Promo credits granted on top of the purchase. |
creditPack.bonusCredits.amount | string | Yes | Integer micros as a string (12500000 = 12.50). |
creditPack.bonusCredits.currency | string | Yes | ISO 4217 currency code: the price's currency. |
creditPack.expiresAfterDays | integer | No | Days until the credits expire (1–3650). |
recurring | object | No | Unused recurring prices only: the billing period and scheme. |
recurring.interval | one of day, week, month, year | Yes | The billing period's unit. |
recurring.intervalCount | integer | No | Periods per billing cycle (default 1). |
recurring.usageType | one of licensed, metered | No | licensed: the quantity is seats or units; metered: the quantity comes from usage events of metered.meter, billed in arrears. |
recurring.billingScheme | one of per_unit, tiered | No | per_unit: unitAmount × quantity; tiered: priced by tiers. |
recurring.unitAmount | object | No | Per-unit prices: the price of one unit per period. |
recurring.unitAmount.amount | string | Yes | Integer micros as a string (12500000 = 12.50). |
recurring.unitAmount.currency | string | Yes | ISO 4217 currency code: the price's currency. |
recurring.tiersMode | one of graduated, volume | No | Tiered prices: graduated (each tier priced separately) or volume (all units at the reached tier). |
recurring.tiers | array of object | No | Tiered prices: the tiers, lowest first. |
recurring.tiers[].upTo | integer or "inf" | Yes | The last unit of the tier (inclusive); "inf" for the last tier. |
recurring.tiers[].unitAmountMicros | string | Yes | Price per unit in micros, as a string; sub-minor precision allowed (2500 = 0.0025). |
recurring.tiers[].flatAmount | object | No | A fixed amount added once when the tier is reached. |
recurring.tiers[].flatAmount.amount | string | Yes | Integer micros as a string (12500000 = 12.50). |
recurring.tiers[].flatAmount.currency | string | Yes | ISO 4217 currency code: the price's currency. |
recurring.trialDays | integer | No | Free trial days for new subscriptions (1–730). |
recurring.includedCredits | object | No | Credits included every period (spec §17). |
recurring.includedCredits.amount | object | Yes | Credits granted into the wallet each period. |
recurring.includedCredits.amount.amount | string | Yes | Integer micros as a string (12500000 = 12.50). |
recurring.includedCredits.amount.currency | string | Yes | ISO 4217 currency code: the price's currency. |
recurring.includedCredits.expiresAfterDays | integer | No | |
recurring.metered | object | No | Metered prices (usageType: metered): the meter and how its usage is aggregated and priced. |
recurring.metered.meter | string | Yes | The meter usage events name, e.g. api.calls or payments.volume. |
recurring.metered.aggregation | one of sum, max, last | No | How a period's usage is aggregated: sum of quantities, max (the largest), or last (the latest event's). |
recurring.metered.pricing | one of per_unit, percent_of_amount | No | per_unit: the price's unitAmount or tiers per unit of usage; percent_of_amount: the quantity is an amount in micros of the price's currency, charged at ratePpm. |
recurring.metered.ratePpm | string | No | percent_of_amount only: the rate in parts per million (0.4% = "4000"). |
recurring.metered.includedQuantity | string | No | Free usage per period, subtracted first (micros of the currency for percent_of_amount). |
recurring.metered.minimumCharge | object | No | The least the price charges per period, usage or not. |
recurring.metered.minimumCharge.amount | string | Yes | Integer micros as a string (12500000 = 12.50). |
recurring.metered.minimumCharge.currency | string | Yes | ISO 4217 currency code: the price's currency. |
recurring.metered.maximumCharge | object | No | The most the price charges per period. |
recurring.metered.maximumCharge.amount | string | Yes | Integer micros as a string (12500000 = 12.50). |
recurring.metered.maximumCharge.currency | string | Yes | ISO 4217 currency code: the price's currency. |
Response
200 OK with a JSON object:
| Field | Type | Description |
|---|---|---|
id | price_… ID | |
object | "price" | |
brandId | brd_… ID | |
livemode | boolean | |
productId | prod_… ID | |
nickname | string or null | |
lookupKey | string or null | |
type | one of one_time, recurring, credit_pack | |
currency | string | |
taxBehavior | one of inclusive, exclusive | |
amount | money or null | Fixed one-time or credit-pack amount. |
customAmount | object or null | The range a buyer may choose from (custom-amount prices). |
creditPack | object or null | |
recurring | object or null | |
active | boolean | |
used | boolean | A checkout session or payment referenced the price: what it charges can no longer change. |
usedAt | date-time or null | |
metadata | object | |
createdAt | date-time | |
updatedAt | date-time |
Examples
Rename a price
PATCH /api/v1/prices/price_01m4tx5nj8emwbyf7y9vcf47y2
Authorization: Bearer or_test_…
Content-Type: application/json
{
"nickname": "Pro monthly (2026)"
}
Response (200):
{
"id": "price_01m4tx5nj8emwbyf7y9vcf47y2",
"object": "price",
"brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
"livemode": false,
"productId": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
"nickname": "Pro monthly (2026)",
"lookupKey": "pro_monthly",
"type": "recurring",
"currency": "EUR",
"taxBehavior": "inclusive",
"amount": null,
"customAmount": null,
"creditPack": null,
"recurring": {
"interval": "month",
"intervalCount": 1,
"usageType": "licensed",
"billingScheme": "tiered",
"unitAmount": null,
"tiersMode": "graduated",
"tiers": [
{
"upTo": 10,
"unitAmountMicros": "12000000",
"flatAmount": null
},
{
"upTo": "inf",
"unitAmountMicros": "9000000",
"flatAmount": null
}
],
"trialDays": 14,
"includedCredits": null,
"metered": null
},
"active": true,
"used": false,
"usedAt": null,
"metadata": {},
"createdAt": "2026-10-13T12:00:00.000Z",
"updatedAt": "2026-10-14T09:30:00.000Z"
}
Errors
| Code | HTTP status | When | What to do |
|---|---|---|---|
validation_failed | 400 | No field to change was sent, one is malformed, or the new terms break a rule. | Fix the fields listed in details.issues and send the request again. |
price_immutable | 409 | The price has been used and the request changes what it charges. | Create a new price with the new terms, move the lookup key to it with prices.move_lookup_key, and archive this one. |
meter_definition_conflict | 409 | New metered terms disagree with another metered price of the meter (aggregation, pricing or currency). | Use the meter's existing aggregation and pricing (and, for percent of amount, its currency), or choose another meter key. |
lookup_key_taken | 409 | Another price of the brand already has the lookup key. | Move the key explicitly with prices.move_lookup_key (POST /prices/{id}/move_lookup_key), or choose another key. |
price_archived | 409 | A lookup key was set on an archived price. | Reactivate the price first (active: true), or use an active price. |
resource_not_found | 404 | No price with this ID is visible to the request. | Check the ID and that your credentials are scoped to the right organization, entity, brand and mode. |
version_conflict | 409 | The price changed at the same time; retry. | Fetch the object again and retry the change. |
permission_denied | 403 | You can't change this brand's catalog. | Ask an organization owner or admin for a role or scope that allows this action. |
It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, scope_required, idempotency_key_reused, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.