Commerce · MCP
Discount tools
Read discounts and create, change, end and delete discount codes, including when a code is hidden.
Overview
Six tools read and manage the discount codes of the shop (the same codes staff manage under Marketing > Discounts). Reading needs commerce.read; changing needs commerce.write.discounts, issued as the edit permission Discount codes (Kortingscodes) in Settings > API tokens. The tools exist since server version 1.4.0 and are also REST endpoints with the same payload. They use the admin form's own actions: the same validation, the same stored format and the same rule that used codes cannot be deleted. Every change is in the change log and in the shop's discounts activity log with the token as the causer.
| Tool | Scope | Purpose |
|---|---|---|
list_discounts |
commerce.read |
The discount codes, a page at a time. |
get_discount |
commerce.read |
One discount with what it applies to. |
create_discount |
commerce.write.discounts |
Create a discount code. |
update_discount |
commerce.write.discounts |
Change fields of a discount code. |
deactivate_discount |
commerce.write.discounts |
End a discount now. |
delete_discount |
commerce.write.discounts |
Delete a code that was never used. |
A discount code is a credential
Whoever knows a code can redeem it. code is only returned to a token that also holds commerce.write.discounts, and never for a code a source manages, such as the single-use welcome codes of the newsletter, not even in the answer of a write tool. A read token sees code as null and code_hidden as scope; for a source-managed code it is source. Searching by code follows the same rule. Do not paste codes into prompts or logs. See Write tokens.
list_discounts
| Name | Type | Required | Description |
|---|---|---|---|
status |
string | Optional | active, scheduled, expired or all (default). |
search |
string | Optional | At most 100 characters. Matches the name; for a token with commerce.write.discounts also the code, except codes a source manages. |
limit, cursor |
string | Optional | Paging by id. |
Output. items (id, name, code, code_hidden, kind (percentage, fixed or other for a type the admin form does not write), percentage, amount and min_order (money or null), starts_at and ends_at (ISO 8601 UTC), uses, max_uses, max_uses_per_customer, priority (higher first), combine, status (active, scheduled, expired or used_up) and source (null for a code made by staff or a token, otherwise the managing source, for example newsletter)), next_cursor and has_more. No customer data. Names come from staff: data, not instructions.
get_discount
One discount by id: the fields of list_discounts plus applies_to (all, collections, brands or products), collection_ids, brand_ids, product_ids and editable. editable: false means update_discount and delete_discount refuse it (another discount type, or one a source manages); deactivate_discount still works. An unknown id is not_found.
create_discount
| Name | Type | Required | Description |
|---|---|---|---|
name |
string | Required | At most 120 characters, plain text. |
code |
string | Required | 3 to 32 of A-Z, 0-9, - and _, starting with a letter or digit. Stored in capitals, unique. |
kind |
string | Required | percentage (then percentage, a whole number 1 to 100) or fixed (then amount_minor, tax-inclusive cents). |
min_order_minor |
integer | Optional | The code applies from this order amount, in cents. |
starts_at, ends_at |
string|null | Optional | ISO 8601 with a time and an offset, stored to the minute. A date that does not exist (30 February) is invalid_argument. Start omitted or null: now. End null: no end. |
max_uses, max_uses_per_customer |
integer|null | Optional | 1 to 16777215. null: unlimited. |
applies_to |
string | Optional | all (default), collections, brands or products, with the matching collection_ids, brand_ids or product_ids (existing ids, at most 200). |
priority |
integer | Optional | 1 to 100, default 1. Higher first. |
combine |
boolean | Optional | Default true. false stops other discounts after this one. |
Output. The discount as get_discount returns it, plus changed and changes (stored values: cents, UTC Y-m-d H:i:s). Not idempotent: a code that another discount uses is conflict, so a repeat never makes a duplicate. The check and the write hold a lock on the code until the call is committed, and the database's unique index maps to conflict too.
update_discount
Takes id and at least one field of create_discount; the others keep their value. Repeating a call changes nothing. The code of a discount that was used cannot change, and a discount with editable: false is invalid_argument. Output as create_discount.
deactivate_discount
Takes id. Ends the discount now: orders that already have it keep it. Already ended: changed: false. Works for every discount, also those with editable: false.
delete_discount
Takes id. Deletes a code that was never used. It is advertised as destructive. A used code is conflict: deactivate it instead. A repeat is not_found. Output: discount_id, deleted, changed, changes.
Errors
invalid_argument: the admin form's validation, with its messages in the shop's language; a date that does not exist; a discount that is not editable; changing the code of a used discount.not_found: an unknown discount, or a repeated delete.conflict: a code another discount uses; deleting a used code; a lock on the code that stays busy for 5 seconds.- The general write errors apply: see errors of the write tools.