Products tools
MCP tools for Products: products_archive, products_create, products_get, products_list, products_pricing_table, products_update.
products_archive: Archive a productproducts_create: Create a productproducts_get: Get a productproducts_list: List productsproducts_pricing_table: Get the pricing tableproducts_update: Update a product
products_archive
Archive a product. Operation products.archive · Brand level · permission catalog:write · risk tier write · since M4
Archives 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.
Annotations: readOnlyHint: false · destructiveHint: true · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
id | ID (prod_…) | yes | – |
reason | string | no | (1–500 characters) |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
idempotency_key | string | no | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters) |
dry_run | boolean | no | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false) |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Idempotency: the result returns the
idempotency_keyused, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours). - Dry run: supported.
dry_run: truechecks permissions and rules and computes the result, then rolls everything back.
Errors
resource_not_found: No product with this ID is visible to the request.version_conflict: The product changed at the same time; retry.permission_denied: You can't change this brand's catalog.
Example
Retire a plan
Arguments:
{
"id": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
"reason": "Replaced by the 2027 plans",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"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"
}
products_create
Create a product. Operation products.create · Brand level · permission catalog:write · risk tier write · since M4
Creates a product in the brand's catalog, in the request's mode (test and live mode have separate catalogs).
taxCategoryId is required: it decides which tax rates apply to the product in every jurisdiction (for
example saas, ebook or electronically_supplied_service). Products of kind: plan appear on the brand's
public pricing table. entitlements grant values of the brand's features (features.create), such as
seats.max = 10; each value must fit its feature's type. Subscriptions grant them while they're active; with
lifetimeEntitlements: true, a one-time purchase grants them for good.
Add prices with prices.create. Images are https URLs.
Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: false · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
name | string | yes | The product's name, shown to customers. (1–200 characters) |
description | string | no | Shown on checkout pages and the pricing table. (1–2000 characters) |
taxCategoryId | one of 9 values, e.g. electronically_supplied_service, saas, ebook | yes | The product's tax category (spec §7.2), e.g. saas or electronically_supplied_service. |
kind | one of standard, plan | no | plan products appear on the brand's pricing table; standard ones don't. (default "standard") |
entitlements | array of object | no | Feature values the product grants (spec §36.1), each feature once. (at most 100 items) (default []) |
lifetimeEntitlements | boolean | no | true: a one-time purchase of the product grants its entitlements for good (spec §36.1). Default false. |
displayOrder | integer | no | Position on the pricing table, lowest first. (0–10000) |
highlighted | boolean | no | Highlight the plan on the pricing table. |
images | array of string | no | Image URLs (https). On updates the whole list is replaced. (at most 8 items) |
metadata | object | no | Your own key-value pairs (at most 50 keys). On updates the whole set is replaced. |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
idempotency_key | string | no | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters) |
dry_run | boolean | no | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false) |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Idempotency: the result returns the
idempotency_keyused, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours). - Dry run: supported.
dry_run: truechecks permissions and rules and computes the result, then rolls everything back.
Errors
org_restricted: Live mode, while the organization's Ownrecord subscription is unpaid (§37.5).validation_failed: A field is missing or malformed, e.g. an unknown tax category.feature_not_found: An entitlement names a feature the brand doesn't have in this mode.entitlement_value_invalid: An entitlement value doesn't fit its feature's type.permission_denied: You can't change this brand's catalog.
Example
A plan with seats and export
Arguments:
{
"name": "Pro",
"description": "For growing teams.",
"taxCategoryId": "saas",
"kind": "plan",
"entitlements": [
{
"featureKey": "seats.max",
"value": 10
},
{
"featureKey": "feature.export",
"value": true
}
],
"displayOrder": 2,
"highlighted": true,
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"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": true,
"images": [],
"metadata": {},
"createdAt": "2026-10-13T12:00:00.000Z",
"updatedAt": "2026-10-13T12:00:00.000Z"
}
products_get
Get a product. Operation products.get · Brand level · permission catalog:read · risk tier read · since M4
Returns one product of the brand's catalog in the request's mode, archived or not: its kind, whether it is
active, its entitlements and its pricing-table hints (displayOrder, highlighted). The brand's pricing
table shows its active products of kind plan.
Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
id | ID (prod_…) | yes | – |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Read-only: changes nothing;
idempotency_keyis ignored.
Errors
resource_not_found: No product with this ID is visible to the request.permission_denied: You can't see this brand's catalog.
Example
A plan
Arguments:
{
"id": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
Result output:
{
"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": true,
"images": [],
"metadata": {},
"createdAt": "2026-10-13T12:00:00.000Z",
"updatedAt": "2026-10-13T12:00:00.000Z"
}
products_list
List products. Operation products.list · Brand level · permission catalog:read · risk tier read · since M4
Lists the brand's products in the request's mode, newest first. Filter with active (true or false) and
kind (plan or standard).
Paginate with limit (1–100, default 10) and starting_after (the next_cursor of the previous page).
Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
active | string | no | Only active (true) or archived (false) products. |
kind | one of standard, plan | no | – |
limit | integer | no | (1–100) |
starting_after | ID (prod_…) | no | – |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Read-only: changes nothing;
idempotency_keyis ignored.
Errors
validation_failed: A filter or pagination value is malformed.permission_denied: You can't see this brand's catalog.
Example
Active plans
Arguments:
{
"active": "true",
"kind": "plan",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
Result output:
{
"object": "list",
"data": [
{
"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": true,
"images": [],
"metadata": {},
"createdAt": "2026-10-13T12:00:00.000Z",
"updatedAt": "2026-10-13T12:00:00.000Z"
}
],
"has_more": false,
"next_cursor": null
}
products_pricing_table
Get the pricing table. Operation products.pricing_table · Brand level · permission catalog:read · risk tier read · since M4
Returns the brand's pricing table: its active products of kind: plan, in display order, with their active
prices and the features each plan grants (by name). Use it to render plans on your own site; it needs no API
key and is rate-limited per IP address.
Only what customers may see is included: no nicknames, metadata or internal fields. Archived products and prices are left out.
Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
brandSlug | string | yes | The brand's slug, e.g. acme-app. (1–64 characters) |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Read-only: changes nothing;
idempotency_keyis ignored.
Errors
resource_not_found: No brand with this slug is visible to the request.
Example
Acme App's plans
Arguments:
{
"brandSlug": "acme-app",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
Result output:
{
"object": "pricing_table",
"brand": {
"id": "brd_01m4tx5nj8emwbyf7y9vcf47x4",
"slug": "acme-app",
"name": "Acme App"
},
"livemode": true,
"products": [
{
"id": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
"name": "Pro",
"description": "For growing teams.",
"images": [],
"highlighted": true,
"displayOrder": 2,
"features": [
{
"key": "seats.max",
"name": "Seats",
"type": "limit",
"value": 10
},
{
"key": "feature.export",
"name": "Export",
"type": "boolean",
"value": true
}
],
"prices": [
{
"id": "price_01m4tx5nj8emwbyf7y9vcf47y2",
"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
}
}
]
}
]
}
products_update
Update a product. Operation products.update · Brand level · permission catalog:write · risk tier write · since M4
Changes a product's name, description, tax category, kind, entitlements, lifetimeEntitlements, pricing-table
hints, images or metadata. Send only the fields to change; null clears an optional value. entitlements,
images and metadata replace the whole list or map. Customers' entitlements are recomputed after a change of
entitlements or lifetimeEntitlements.
A new tax category applies to future sales; issued invoices keep theirs. active: false archives the product
(as products.archive) and active: true reactivates it.
Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
id | ID (prod_…) | yes | – |
name | string | no | (1–200 characters) |
description | string or null | no | – |
taxCategoryId | one of 9 values, e.g. electronically_supplied_service, saas, ebook | no | The product's tax category (spec §7.2), e.g. saas or electronically_supplied_service. |
kind | one of standard, plan | no | plan products appear on the brand's pricing table; standard ones don't. |
entitlements | array of object | no | Feature values the product grants (spec §36.1), each feature once. (at most 100 items) |
lifetimeEntitlements | boolean | no | true: a one-time purchase grants the entitlements for good. Buyers' entitlements follow. |
displayOrder | integer or null | no | – |
highlighted | boolean | no | – |
images | array of string | no | Image URLs (https). On updates the whole list is replaced. (at most 8 items) |
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 product, true reactivates it. |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
idempotency_key | string | no | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters) |
dry_run | boolean | no | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false) |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Idempotency: the result returns the
idempotency_keyused, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours). - Dry run: supported.
dry_run: truechecks permissions and rules and computes the result, then rolls everything back.
Errors
validation_failed: No field to change was sent, or one is malformed.feature_not_found: An entitlement names a feature the brand doesn't have in this mode.entitlement_value_invalid: An entitlement value doesn't fit its feature's type.resource_not_found: No product with this ID is visible to the request.version_conflict: The product changed at the same time; retry.permission_denied: You can't change this brand's catalog.
Example
Raise the seat limit
Arguments:
{
"id": "prod_01m4tx5nj8emwbyf7y9vcf47y0",
"entitlements": [
{
"featureKey": "seats.max",
"value": 25
},
{
"featureKey": "feature.export",
"value": true
}
],
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"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": 25
},
{
"featureKey": "feature.export",
"value": true
}
],
"lifetimeEntitlements": false,
"displayOrder": 2,
"highlighted": true,
"active": true,
"images": [],
"metadata": {},
"createdAt": "2026-10-13T12:00:00.000Z",
"updatedAt": "2026-10-14T09:30:00.000Z"
}