Archive a product
The products.archive operation: POST /api/v1/products/{id}/archive in the REST API and the products_archive tool in the MCP server.
/api/v1/products/{id}/archiveArchives a product: it leaves the pricing table, can't be sold and can't get new prices. Existing
subscriptions, invoices and the product's prices stay as they are. Archiving an archived product changes
nothing. Reactivate it with products.update and active: true.
reason is recorded in the audit log.
At a glance
- REST:
POST /api/v1/products/{id}/archive - MCP tool:
products_archive - Operation ID:
products.archive - Scope: Brand
- Permission:
catalog:write - Risk tier:
write - Dry run: Supported (send
Ownrecord-Dry-Run: true) - Idempotency:
Idempotency-Keyrequired - Modes: Test and live
- Authentication: API key with the
catalog:writescope - Since: M4
Request
Path parameters
| Field | Type | Description |
|---|---|---|
id | prod_… ID |
Body
A JSON object (Content-Type: application/json):
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | No |
Response
200 OK with a JSON object:
| Field | Type | Description |
|---|---|---|
id | prod_… ID | |
object | "product" | |
brandId | brd_… ID | |
livemode | boolean | |
name | string | |
description | string or null | |
taxCategoryId | one of 9 values, e.g. electronically_supplied_service, saas, ebook (all in the OpenAPI document) | |
kind | one of standard, plan | |
entitlements | array of object | |
entitlements[].featureKey | string | |
entitlements[].value | boolean or number or string | |
lifetimeEntitlements | boolean | A one-time purchase of the product grants its entitlements for good (spec §36.1). |
displayOrder | integer or null | |
highlighted | boolean | |
active | boolean | |
images | array of string | |
metadata | object | |
createdAt | date-time | |
updatedAt | date-time |
Examples
Retire a plan
POST /api/v1/products/prod_01m4tx5nj8emwbyf7y9vcf47y0/archive
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json
{
"reason": "Replaced by the 2027 plans"
}
Response (200):
{
"id": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
"object": "product",
"brandId": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
"livemode": false,
"name": "Pro",
"description": "For growing teams.",
"taxCategoryId": "saas",
"kind": "plan",
"entitlements": [
{
"featureKey": "seats.max",
"value": 10
},
{
"featureKey": "feature.export",
"value": true
}
],
"lifetimeEntitlements": false,
"displayOrder": 2,
"highlighted": true,
"active": false,
"images": [],
"metadata": {},
"createdAt": "2026-10-13T12:00:00.000Z",
"updatedAt": "2026-10-14T09:30:00.000Z"
}
Errors
| Code | HTTP status | When | What to do |
|---|---|---|---|
resource_not_found | 404 | No product 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 product 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: validation_failed, api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, scope_required, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.