wc_update_coupon: update a coupon
Changes an existing coupon. Only the fields you pass are touched.
Arguments
| Argument | Required | Meaning |
|---|---|---|
id |
Yes | The coupon |
code |
No | The code customers type |
discount_type |
No | percent, fixed_cart or fixed_product |
amount |
No | The discount value |
description |
No | Internal note |
date_expires |
No | When it stops working |
usage_limit |
No | Total redemptions allowed |
individual_use |
No | Prevent combining with other coupons |
product_ids |
No | Restrict to specific products |
dry_run |
No | Report without writing |
Permissions
Allow WooCommerce catalog writes open, plus manage_woocommerce or edit_shop_coupons.
The dry run's after is not the result
This is the trap specific to this tool. The dry run returns:
before— the coupon as it is now, fully formatted and accurate.after— the arguments you sent, unprocessed.
after is not the coupon that would result. It does not merge your changes into the existing record, and a field you did not send simply does not appear there — which looks, at a glance, as if it would be cleared.
Read before closely; it is real and it is your record. Treat after as an echo of your request, and work out the resulting coupon yourself:
Dry-run the change, show me the
before, and tell me what every field will be afterwards.
Amount and type must be reasoned about together
Changing amount from 10 to 25 on a percent coupon is a large giveaway. Changing discount_type from fixed_cart to percent while leaving amount at 20 turns €20 off into 20% off — on a €500 order, that is €100.
The before tells you the current type. Check it before changing the amount, and never change both in one call without stating the resulting behaviour first.
Changing code breaks the code in circulation
The coupon keeps its ID and its history, but the string customers type changes. Anyone holding the old code gets "coupon does not exist" at checkout.
If a code has been publicised, do not rename it. Create a new coupon and expire the old one.
Expiring is the safe way to retire a coupon
Setting date_expires to a past or imminent date stops the coupon working without deleting anything. The record stays readable, the code stays reserved, and it can be reactivated by changing the date back.
Prefer this to wc_delete_coupon for anything that has been used.
To remove an expiry — making the coupon permanent — you would clear the field, which is rarely what anyone wants. Be explicit if you intend it.
Past orders are unaffected
Editing a coupon does not retroactively change orders that already used it. What changes is what the code does from now on.
That is reassuring for accounting and unhelpful for damage control: if a code was over-generous for an hour, the orders placed in that hour keep their discount.
usage_limit below current usage
Lowering the limit under the number of redemptions already made stops the coupon working immediately. That is a legitimate way to kill a code fast — faster than editing dates, since it needs no reasoning about timezones.
MCP cannot show you the current usage count, so you cannot calculate the margin. Set it to 1 if the intent is "stop this now".
After writing
- Read the coupon back with
wc_get_coupon— not just the tool's response. - Test the code in a cart if the amount or type changed.
- Confirm the expiry behaves as intended against the site's timezone.
Common problems
| Symptom | Cause |
|---|---|
| The write is refused | Catalog write gate closed |
pom_ai_mcp_wc_coupon_not_found |
Wrong ID, or the code was passed instead |
pom_ai_mcp_wc_forbidden |
Missing manage_woocommerce or edit_shop_coupons |
The after looks like fields were cleared |
It echoes your arguments; unsent fields are unchanged |
| The discount is far off | discount_type and amount disagree |
| Customers report the code is invalid | code was renamed, or the limit was reached |
| The coupon still works after expiring | Timezone, or a cached checkout |
Related
wc_get_coupon— read first; this is your only recordwc_create_couponwc_delete_coupon