Coupons and promotion codes
Discount codes in Áskell are made up of two objects that work together:
A coupon (
coupon) defines the discount itself: a fixed amount (amount_offandcurrency) or a percentage (percent_off), how long it applies (duration:forever,onceorrepeatingwithduration_in_months) and limits such asmax_redemptionsandredeem_by.A promotion code (
promotion_code) is the code the customer enters (code), and it points to a coupon. You can create many codes for the same coupon, restrict a code to a single customer, and set an expiry date (expires_at) and a minimum amount inrestrictions.
Both objects can be created, fetched, updated and deleted through the V2 API. All calls require a secret API key. Legacy token authentication is not supported on these endpoints:
Authorization: Api-Key your-secret-api-key
Full documentation of fields and responses is in our Swagger documentation under V2 Coupons at /api/swagger/v2/.
Coupons
Endpoint |
Description |
|---|---|
|
Lists coupons. Filters: |
|
Creates a coupon. |
|
Retrieves a single coupon. |
|
Partially updates a coupon. |
|
Deletes a coupon (soft delete). |
Example of creating a 20% coupon that applies for three months:
{
"name": "Sumartilboð",
"percent_off": "20",
"duration": "repeating",
"duration_in_months": 3,
"max_redemptions": 100,
"redeem_by": "2026-12-31T23:59:59Z"
}
Rules:
Exactly one of
amount_off(together withcurrency) orpercent_offmust be set. To switch from one to the other withPATCH, send the old field asnullin the same call.duration_in_monthsis required whendurationisrepeatingand must not be set otherwise.redeem_bymust be in the future unless the coupon has already expired; an expired coupon can still be updated and deleted, but a valid coupon cannot be made to expire by setting a date in the past.Unknown fields in
POSTandPATCHare rejected with400.metadataandrestrictionscan be sent asnullto clear them.idandtimes_redeemedcannot be changed.idcan be supplied on creation (letters, digits, underscores, hyphens and periods, at most 128 characters); otherwise it is generated automatically.currencymust be a valid three-letter ISO 4217 code.max_redemptionsandduration_in_monthsmust be 1 or higher.A coupon that has been redeemed (
times_redeemed> 0) cannot be deleted. Useredeem_byormax_redemptionsto close it.
Limiting a coupon to plans and products
A coupon can be limited to specific legacy plans (applies_to_plans, a list of plan ids), to specific variants of them (applies_to_plan_variants, a list of plan variant ids), to specific products (applies_to_products, a list of product ids) and to specific prices of them (applies_to_prices, a list of price ids: the same id that GET /api/v2/catalog/prices/ returns and an offer line’s price). All four lists are empty by default, and the coupon then applies to everything:
{
"name": "Afsláttur af grunnpakka",
"percent_off": "10",
"duration": "forever",
"applies_to_products": [42]
}
As soon as any of the lists has an entry the coupon is restricted: a legacy subscription only gets the discount if its plan is in
applies_to_plansor its plan variant inapplies_to_plan_variants, and a contract line only if its product is inapplies_to_productsor its price inapplies_to_prices. A coupon limited only to plans or plan variants therefore gives no discount on contracts, and the other way round.A plan in
applies_to_planscovers all of its variants, while a plan variant inapplies_to_plan_variantscovers only itself. That way a coupon can, for example, discount a monthly subscription without giving the same discount on a prepaid year of the same plan.In the same way, a product in
applies_to_productscovers all of its prices, while a price inapplies_to_pricesonly covers itself. A coupon can, for example, discount a product’s monthly price but not the yearly price of the same product:{ "name": "Fyrsti mánuðurinn á hálfvirði", "percent_off": "50", "duration": "once", "applies_to_prices": [101] }
On a contract the discount is calculated from the lines it covers alone:
percent_offis a percentage of those lines andamount_offis at most their total.A contract line is judged by the price it is on at the time. If an item moves from a monthly price the coupon is limited to onto a yearly price it is not limited to, it gets no discount, and gets it again if it moves back.
A code is refused when nothing in the purchase, or on the contract it is applied to, is covered by the coupon.
If a subscription moves to a plan or plan variant outside the lists, the discount stays on it but takes nothing off until it moves back to a plan or plan variant the coupon covers. A
oncecoupon is not used up by a payment it did not reduce.Plans, plan variants, products and prices must belong to the same account. In a
PATCH, a list that is left out stays unchanged and an empty list ([]) clears it.A plan, plan variant, product or price that a coupon is limited to cannot be deleted, nor can a plan with a variant, or a product with a price, that a coupon is limited to.
Promotion codes
Endpoint |
Description |
|---|---|
|
Lists promotion codes. Filters: |
|
Creates a promotion code. |
|
Retrieves a single promotion code. |
|
Partially updates a promotion code. |
|
Deletes a promotion code (soft delete). |
Example of creating a code that a single customer can redeem only once:
{
"coupon": "coup_5f3a1c2b9d8e4f6a7b8c9d0e",
"code": "VELKOMIN",
"customer_reference": "customer-123",
"max_redemptions": 1,
"expires_at": "2026-12-31T23:59:59Z",
"restrictions": {
"minimum_amount": "1000",
"minimum_amount_currency": "ISK"
}
}
Rules:
couponmust be a coupon on the same account.codeis 4-50 characters (letters, digits, hyphens and underscores) and is always stored in uppercase. If it is omitted, a code is generated automatically. The code must be unique among the account’s active codes; inactive (active: false) and deleted codes free the code up for reuse.The customer is given with
customer(ID) orcustomer_reference, not both.nullremoves the customer binding.restrictionssupports only a minimum amount:minimum_amount(greater than 0) andminimum_amount_currency(ISO 4217 code) must be sent together. An empty{}removes the restriction.A promotion code that has been redeemed cannot be deleted. Set
activetofalseinstead.
Applying codes to subscriptions is documented with the subscription endpoints: see POST /api/v2/subscription-contracts/{contractId}/apply-code/ for V2 contracts and POST /api/subscriptions/{subscription_id}/apply-code/ for legacy subscriptions.