store/schedule-sale puts a product on sale, optionally between two dates, or ends a sale with clear.
A sale price that is not below the regular price is refused rather than saved.
At a glance
| Ability | store/schedule-sale |
| Toolset | WooCommerce — toolset/woocommerce |
| Group | WooCommerce › Pricing & Sales |
| Requires | WooCommerce, active on the site |
| Capability | manage_options |
| Safety | Writes data |
| Repeatable | Idempotent — running it twice leaves the same result |
| Ships in | AcrossAI Abilities Manager 0.0.34 and later |
Why the save path matters more here than anywhere
Two things about sales are computed during the save rather than read at display time. The first is the displayed price: WooCommerce works out whether a sale is currently active and writes the effective price into the product. The second is the on-sale product list, which is cached.
On top of that, the on-sale and featured product lists are cached, and the cache is held for thirty days. A sale written outside WooCommerce’s save path can leave a shop off-sale for a month with nothing anywhere suggesting a problem.
So a sale written by any other route — a direct meta write, an import — can produce a product whose sale dates are perfectly correct and which the shop refuses to show as on sale for the next month. This goes through the proper path and reports the lookup state afterwards.
The refusal on a non-lower sale price is the other half. WooCommerce silently discards a sale price that is not below the regular price; without the check, setting a sale price of £30 on a £25 product returns success and does nothing at all.
Dates are optional. Without them the sale is immediate and open-ended.
Input
| Name | Type | Required | What it is |
|---|---|---|---|
id | integer | Yes | Product ID. |
sale_price | string | No | Sale price. Must be below the regular price. |
from | string | No | Start date, YYYY-MM-DD. |
to | string | No | End date, YYYY-MM-DD. |
clear | boolean | No | End the sale and remove any schedule. |
What comes back
| Name | Type | What it is |
|---|---|---|
product | object | The product after the write. |
lookup_state | object | Whether the product lookup table still agrees with the product after the write. A mismatch means the shop is answering SKU searches, price sorts and on-sale queries with stale values. |
success | boolean | Whether the call completed. |
message | string | A one-line summary of what happened, suitable for showing a human. |
error_code | string | Present only on failure — a stable machine-readable reason, such as a missing field, a wrong field type or an unmet confirmation. |
Example
Ask your assistant:
Put product 812 on sale at £19 for the first week of December.
It resolves to one call:
{
"ability": "store/schedule-sale",
"parameters": {
"id": 812,
"sale_price": "19.00",
"from": "2026-12-01",
"to": "2026-12-07"
}
}Worth knowing
- A sale price not below the regular price is refused, not silently discarded.
- The on-sale list is cached for thirty days. This is why sales must go through the proper save path.
clearends the sale and removes the schedule together.- Idempotent.
Related abilities
- Bulk Update Prices — change regular prices across a set
- Get Store Status — check the cached on-sale list
- Update Variation — sale pricing on one variation
Get the plugins:
AcrossAI Abilities Manager · AcrossAI MCP Manager
Browse the rest: Every ability, by category