What actually goes in the markup
There is no Coupon type in schema.org. What people mean by coupon schema is an Offer — usually nested inside a Product — carrying the discount's terms.
The fields that matter are the price and its currency, the availability, and above all the validity window. validFrom and validThrough are what let a search engine know an offer has ended; without them, an expired promotion has no way of signalling that it is expired, and it will keep being presented as current until the page is recrawled and the text happens to change.
{
"@context": "https://schema.org",
"@type": "Offer",
"name": "20% off everything",
"price": "39.99",
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"validFrom": "2026-09-01",
"validThrough": "2026-09-30"
}