Coupons
Discount codes shoppers type at checkout: a percentage or a fixed amount off, with limits on who, when and how often.
Reach them through $admin->coupons. Reading needs the marketing:read scope, changing them marketing:write.
List coupons
$admin->coupons->list(array $query = []): array
One page of the shop's coupons, newest first, or oldest change first with updatedSince. Read the next page with meta.nextCursor as cursor. Scope: marketing:read.
Parameters
| Parameter |
Type |
|
$query |
array |
The query fields below, by name. |
Query fields
| Parameter | Type | Description |
|---|
code | string | An exact code (case-insensitive). At most 255 characters. |
limit | integer | At least 1. At most 100. Default 50. |
cursor | string | meta.nextCursor (or the cursor in links.next) of the previous page. At most 1000 characters. |
updatedSince | string (date-time) | Records changed at or after this time (ISO 8601, any offset or Z), oldest change first, for incremental sync. |
Returns
An array with data (a list of AdminCoupon), links and meta:
| Field | Type | Description |
|---|
links | object | |
links.first | null | |
links.last | null | |
links.prev | string (uri) or null | |
links.next | string (uri) or null | |
meta | object | |
meta.path | string (uri) | |
meta.perPage | integer | |
meta.nextCursor | string or null | |
meta.prevCursor | string or null | |
data | array of AdminCoupon | |
data[].id | integer | |
data[].code | string | |
data[].type | string | One of percentage, fixed. |
data[].value | number | |
data[].minOrderValue | number or null | |
data[].maxDiscountAmount | number or null | |
data[].usageLimit | integer or null | |
data[].usageLimitPerCustomer | integer or null | |
data[].usedCount | integer or null | |
data[].autoApply | boolean | |
data[].firstOrderOnly | boolean | |
data[].combinableWithOffers | boolean | |
data[].startsAt | string (date-time) or null | |
data[].endsAt | string (date-time) or null | |
data[].status | boolean | |
data[].createdAt | string (date-time) or null | |
data[].updatedAt | string (date-time) or null | |
Errors
| Status | When |
|---|
401 | invalid_api_key: no active Admin key in Authorization: Bearer. |
403 | admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope. |
422 | Validation errors ({ message, errors }), or an idempotency refusal(idempotency_key_reused, idempotency_key_invalid). |
429 | Rate limited. |
Example
$page = $admin->coupons->list(['code' => 'WELCOME10']);
$coupon = $page['data'][0] ?? null;
Iterate over every coupon
$admin->coupons->all(array $query = []): Generator
Every coupon matching the query, one at a time, fetching the next page as you read. It takes the same query as list, without cursor. Scope: marketing:read.
Returns
A generator of AdminCoupon arrays, each:
| Field | Type | Description |
|---|
[].id | integer | |
[].code | string | |
[].type | string | One of percentage, fixed. |
[].value | number | |
[].minOrderValue | number or null | |
[].maxDiscountAmount | number or null | |
[].usageLimit | integer or null | |
[].usageLimitPerCustomer | integer or null | |
[].usedCount | integer or null | |
[].autoApply | boolean | |
[].firstOrderOnly | boolean | |
[].combinableWithOffers | boolean | |
[].startsAt | string (date-time) or null | |
[].endsAt | string (date-time) or null | |
[].status | boolean | |
[].createdAt | string (date-time) or null | |
[].updatedAt | string (date-time) or null | |
Example
foreach ($admin->coupons->all(['updatedSince' => $lastSyncedAt]) as $coupon) {
$erp->saveCoupon($coupon);
}
Get a coupon
$admin->coupons->get(int $id): array
One coupon by its id. Scope: marketing:read.
Parameters
| Parameter |
Type |
|
$id |
int |
The coupon's id. |
Returns
An AdminCoupon:
| Field | Type | Description |
|---|
id | integer | |
code | string | |
type | string | One of percentage, fixed. |
value | number | |
minOrderValue | number or null | |
maxDiscountAmount | number or null | |
usageLimit | integer or null | |
usageLimitPerCustomer | integer or null | |
usedCount | integer or null | |
autoApply | boolean | |
firstOrderOnly | boolean | |
combinableWithOffers | boolean | |
startsAt | string (date-time) or null | |
endsAt | string (date-time) or null | |
status | boolean | |
createdAt | string (date-time) or null | |
updatedAt | string (date-time) or null | |
Errors
| Status | When |
|---|
401 | invalid_api_key: no active Admin key in Authorization: Bearer. |
403 | admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope. |
404 | not_found: the shop has no such record. |
429 | Rate limited. |
Create a coupon
$admin->coupons->create(array $input, string|false|null $idempotencyKey = null): array
A new coupon. The code is stored in upper case and must be unique in the shop. Scope: marketing:write.
Parameters
| Parameter |
Type |
|
$input |
array |
The coupon's fields, below. |
$idempotencyKey |
string|false|null |
Your own Idempotency-Key, or false for none. One is made for you when null. |
Request fields
| Field | Type | Description |
|---|
code required | string | Unique in the shop; stored in upper case. At most 50 characters. |
type required | string | One of percentage, fixed. |
value required | number | At most 100 for a percentage. At least 0. |
minOrderValue | number or null | At least 0. |
maxDiscountAmount | number or null | At least 0. |
usageLimit | integer or null | At least 1. |
usageLimitPerCustomer | integer or null | At least 1. |
autoApply | boolean or null | |
firstOrderOnly | boolean or null | |
combinableWithOffers | boolean or null | |
startsAt | string (date-time) or null | |
endsAt | string (date-time) or null | |
taxonomyFilters | object (map) or null | Limits the coupon to term ids, by taxonomy type id. Not returned in responses. |
taxonomyLabels | object (map) or null | Not returned in responses. |
status | boolean or null | |
Returns
The new AdminCoupon:
| Field | Type | Description |
|---|
id | integer | |
code | string | |
type | string | One of percentage, fixed. |
value | number | |
minOrderValue | number or null | |
maxDiscountAmount | number or null | |
usageLimit | integer or null | |
usageLimitPerCustomer | integer or null | |
usedCount | integer or null | |
autoApply | boolean | |
firstOrderOnly | boolean | |
combinableWithOffers | boolean | |
startsAt | string (date-time) or null | |
endsAt | string (date-time) or null | |
status | boolean | |
createdAt | string (date-time) or null | |
updatedAt | string (date-time) or null | |
Errors
| Status | When |
|---|
401 | invalid_api_key: no active Admin key in Authorization: Bearer. |
403 | admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope. |
409 | idempotency_in_progress: a request with this Idempotency-Key is still running. Retry with the same key after Retry-After seconds; the first answer is then replayed. |
422 | Validation errors ({ message, errors }), or an idempotency refusal(idempotency_key_reused, idempotency_key_invalid). |
429 | Rate limited. |
Example
$coupon = $admin->coupons->create([
'code' => 'WELCOME10',
'type' => 'percentage',
'value' => 10,
'firstOrderOnly' => true,
'usageLimitPerCustomer' => 1,
'endsAt' => '2026-12-31T23:59:59Z',
]);
Update a coupon
$admin->coupons->update(
int $id,
array $changes,
DateTimeInterface|string|null $unmodifiedSince = null,
string|false|null $idempotencyKey = null,
): array
Changes only the fields sent; the coupon must still pass the full rules. Setting status to false switches it off. Scope: marketing:write.
Parameters
| Parameter |
Type |
|
$id |
int |
The coupon's id. |
$changes |
array |
The fields to change, below. |
$unmodifiedSince |
DateTimeInterface|string|null |
The coupon's updatedAt as you read it. If it changed since, the change is refused with 409 edit_conflict. |
$idempotencyKey |
string|false|null |
Your own Idempotency-Key, or false for none. |
Request fields
| Field | Type | Description |
|---|
code | string | Unique in the shop; stored in upper case. At most 50 characters. |
type | string | One of percentage, fixed. |
value | number | At most 100 for a percentage. At least 0. |
minOrderValue | number or null | At least 0. |
maxDiscountAmount | number or null | At least 0. |
usageLimit | integer or null | At least 1. |
usageLimitPerCustomer | integer or null | At least 1. |
autoApply | boolean or null | |
firstOrderOnly | boolean or null | |
combinableWithOffers | boolean or null | |
startsAt | string (date-time) or null | |
endsAt | string (date-time) or null | |
taxonomyFilters | object (map) or null | Limits the coupon to term ids, by taxonomy type id. Not returned in responses. |
taxonomyLabels | object (map) or null | Not returned in responses. |
status | boolean or null | |
updatedAt | string (date-time) or null | The record's updatedAt as you read it; a newer record gets 409 edit_conflict. |
Returns
The changed AdminCoupon:
| Field | Type | Description |
|---|
id | integer | |
code | string | |
type | string | One of percentage, fixed. |
value | number | |
minOrderValue | number or null | |
maxDiscountAmount | number or null | |
usageLimit | integer or null | |
usageLimitPerCustomer | integer or null | |
usedCount | integer or null | |
autoApply | boolean | |
firstOrderOnly | boolean | |
combinableWithOffers | boolean | |
startsAt | string (date-time) or null | |
endsAt | string (date-time) or null | |
status | boolean | |
createdAt | string (date-time) or null | |
updatedAt | string (date-time) or null | |
Errors
| Status | When |
|---|
401 | invalid_api_key: no active Admin key in Authorization: Bearer. |
403 | admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope. |
404 | not_found: the shop has no such record. |
409 | edit_conflict (the record changed after If-Unmodified-Since or updatedAt), or idempotency_in_progress. |
422 | Validation errors ({ message, errors }), or an idempotency refusal(idempotency_key_reused, idempotency_key_invalid). |
429 | Rate limited. |
Example
$coupon = $admin->coupons->get(5);
$admin->coupons->update(5, ['value' => 15], unmodifiedSince: $coupon['updatedAt']);
Delete a coupon
$admin->coupons->delete(int $id): void
Deletes a coupon. Scope: marketing:write.
Parameters
| Parameter |
Type |
|
$id |
int |
The coupon's id. |
Returns
Nothing.
Errors
| Status | When |
|---|
401 | invalid_api_key: no active Admin key in Authorization: Bearer. |
403 | admin_key_in_browser (an Origin header was sent), ip_not_allowed, plan_required(the shop's plan lacks the Integration API, or the feature the endpoint needs), orinsufficient_scope. |
404 | not_found: the shop has no such record. |
409 | idempotency_in_progress: a request with this Idempotency-Key is still running. Retry with the same key after Retry-After seconds; the first answer is then replayed. |
422 | Validation errors ({ message, errors }), or an idempotency refusal(idempotency_key_reused, idempotency_key_invalid). |
429 | Rate limited. |