Discount Coupons
The seven endpoints that define discount coupons, copy them and set their conditions.
Overview
Coupons are the discount codes a client uses in the basket or on an invoice. A coupon takes off either a share or a fixed amount. The type field names which of the two, and the matching field is the one to fill.
When a coupon is valid rests on three things: its stored status, its date range and its use limit. The listing folds the three together and returns the real state as well, and that is what a client meets.
The conditions cover the rest: which products, which cycles, which kind of client and the smallest basket it works on. The list of product values comes from an endpoint of its own.
Reference
Listing the Coupons
Returns the discount coupons with the state they are really in.
curl 'https://panel.example.com/api/v1/admin/financial/coupons?status=active' \
-H "Authorization: Bearer $API_KEY"const url = new URL('https://panel.example.com/api/v1/admin/financial/coupons');
url.searchParams.set('status', 'active');
const res = await fetch(url, {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/financial/coupons?' . http_build_query(['status' => 'active']));
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// There are two status fields: the stored one and the REAL one. Clients meet the second.
$rows = Api::Financial()->GetCoupons()['data'];
$live = array_filter($rows, fn ($c) => $c['effective_status'] === 'active');Creating a Coupon
Defines a new discount coupon.
percentage or amount. A share by default.curl -X POST 'https://panel.example.com/api/v1/admin/financial/coupons' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"code":"HOSGELDIN30","type":"percentage","rate":30,"max_uses":50}'const res = await fetch('https://panel.example.com/api/v1/admin/financial/coupons', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
code: 'WELCOME30',
type: 'percentage',
rate: 30,
max_uses: 50,
due_date: '2026-12-31',
}),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/financial/coupons');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'code' => 'WELCOME30',
'type' => 'percentage',
'rate' => 30,
'max_uses' => 50,
]),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// A coupon is born LIVE, and with no end date it NEVER EXPIRES; weigh the two together.
Api::Financial()->CreateCoupon([
'code' => 'WELCOME30',
'rate' => 30,
'max_uses' => 50,
'due_date' => '2026-12-31',
]);Reading the Product Tree
Returns the products and categories a coupon can be tied to.
curl 'https://panel.example.com/api/v1/admin/financial/coupons/products-hierarchy' \
-H "Authorization: Bearer $API_KEY"const res = await fetch('https://panel.example.com/api/v1/admin/financial/coupons/products-hierarchy', {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/financial/coupons/products-hierarchy');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Do not write the values into your code: the list follows the installation's own products.
$options = Api::Financial()->GetCouponProductsHierarchy()['data'];Reading One Coupon
Returns one coupon with all of its conditions.
curl 'https://panel.example.com/api/v1/admin/financial/coupons/19' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/financial/coupons/${id}`, {
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/financial/coupons/' . $id);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The detail carries NO real-state field; only the list works that out.
$coupon = Api::Financial()->GetCoupon(['id' => $id])['data'];Updating a Coupon
Changes the coupon fields you send.
percentage or amount. A share by default.curl -X PATCH 'https://panel.example.com/api/v1/admin/financial/coupons/19' \
-H "Authorization: Bearer $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"rate":25,"due_date":"2027-01-31"}'const res = await fetch(`https://panel.example.com/api/v1/admin/financial/coupons/${id}`, {
method: 'PATCH',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ rate: 25, due_date: '2027-01-31', auto_apply: true }),
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/financial/coupons/' . $id);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['rate' => 25, 'due_date' => '2027-01-31']),
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Changing the rate does not reach PAST orders; it touches later uses alone.
Api::Financial()->UpdateCoupon(['id' => $id, 'rate' => 25]);Deleting a Coupon
Removes a coupon.
curl -X DELETE 'https://panel.example.com/api/v1/admin/financial/coupons/19' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/financial/coupons/${id}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${apiKey}` },
});
const body = await res.json();$ch = curl_init('https://panel.example.com/api/v1/admin/financial/coupons/' . $id);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// Switch it off rather than delete: the code stays taken and its history survives.
Api::Financial()->UpdateCoupon(['id' => $id, 'status' => 'inactive']);Copying a Coupon
Opens a new coupon carrying an existing one's settings.
curl -X POST 'https://panel.example.com/api/v1/admin/financial/coupons/19/duplicate' \
-H "Authorization: Bearer $API_KEY"const res = await fetch(`https://panel.example.com/api/v1/admin/financial/coupons/${id}/duplicate`, {
method: 'POST',
headers: { Authorization: `Bearer ${apiKey}` },
});
const { data } = await res.json();
console.log(data.code); // WELCOME30-COPY$ch = curl_init('https://panel.example.com/api/v1/admin/financial/coupons/' . $id . '/duplicate');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
]);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);// The copy is born OFF: fix its code and dates, then switch it on yourself.
$copy = Api::Financial()->DuplicateCoupon(['id' => $id])['data'];
Api::Financial()->UpdateCoupon([
'id' => $copy['id'], 'code' => 'SUMMER30', 'status' => 'active',
]);Pitfalls
The stored status is the switch an operator flips. The real state is worked out with the date range and the use limit. A coupon that reads live may not work because it expired or was used up. The second field is what tells you what a client will meet, and it comes back on the listing alone.
A coupon left without an end date never stops. A code opened for a campaign and forgotten still takes money off months later. With the use limit at zero as well it is both endless and unlimited. Fill in at least one of the two on a campaign code.
The duplicate endpoint opens the new coupon switched off. It also adds a copy suffix to the code, clears the use count and drops the start date. The copy is not ready to use: fix its code and switch it on. Duplicating the same coupon twice numbers the suffix upward.
Changing a coupon's rate or its conditions touches later uses. Orders and invoices already cut with it keep the old rate. That is right, because those documents tell the story of a moment. Correcting a mistake means going to the invoice itself as well.
The values naming which products a coupon applies to come from a separate endpoint and follow the installation's own product tree. Writing them into your code leaves a coupon quietly matching nothing on another installation, or once the products change. Read the list each time.
Related Articles
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.