Promotions
Promotions apply automatic discounts to products. A promotion can target all products, or be scoped to specific products, collections, or variants via targets. When a promotion has no targets, it applies to all products in the store.
Promotions support two discount types: percentage (e.g. 20% off) and fixed_amount (e.g. $5 off, in cents). The price_targets field controls which price levels or customer groups are affected (e.g. base price only, a specific tier price key, or a customer group ID).
Base URL: https://api.hydrajs.dev
Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/v1/promotions |
Secret | List promotions |
POST |
/v1/promotions |
Secret | Create a promotion |
GET |
/v1/promotions/{id} |
Secret | Get a promotion |
PATCH |
/v1/promotions/{id} |
Secret | Update a promotion |
DELETE |
/v1/promotions/{id} |
Secret | Delete a promotion |
List promotions
GET /v1/promotions
Returns a paginated list of promotions with their targets.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
integer | 25 |
Results per page (1–250) |
cursor |
string | - | Pagination cursor from a previous response |
sort |
string | created_at |
Sort field: created_at, updated_at, name |
order |
string | desc |
Sort direction: asc, desc |
status |
string | - | Filter by status: active, disabled, archived |
search |
string | - | Filter by name (case-insensitive substring match) |
fields |
string | - | Comma-separated fields to return |
Request
curl https://api.hydrajs.dev/v1/promotions?status=active&limit=10 \
-H "Authorization: Bearer sk_live_YOUR_KEY"
Response 200
{
"data": [
{
"id": "promo_abc123def456ghij",
"name": "Summer Sale",
"type": "percentage",
"value": 20,
"status": "active",
"price_targets": ["base"],
"starts_at": "2026-08-01T00:00:00Z",
"ends_at": "2026-09-01T00:00:00Z",
"targets": [
{
"id": "ptgt_abc123def456ghij",
"target_type": "collection",
"target_id": "col_abc123",
"target_name": "Summer Collection"
}
],
"created_at": "2026-07-15T09:30:00Z",
"updated_at": "2026-07-15T09:30:00Z"
}
],
"pagination": {
"cursor": "eyJ0IjoiMjAyNi...",
"has_more": false,
"total": 1
}
}
ℹPagination
All list endpoints use cursor-based pagination. Pass the cursor value from the response to fetch
the next page.
Create a promotion
POST /v1/promotions
Creates a new promotion. Returns the created promotion with resolved target names.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Promotion name (1–255 chars) |
type |
string | Yes | Discount type: percentage, fixed_amount |
value |
integer | Yes | Discount value (1–100 for percentage, cents for fixed) |
status |
string | No | active (default) or disabled |
price_targets |
string[] | No | Price level or customer group to target. Accepts ["base"] (default), ["*"] (all levels), a price tier key (e.g. ["wholesale"]), or a customer group ID (e.g. ["cg_abc123"]). Single value. |
starts_at |
string | Yes | ISO 8601 start datetime |
ends_at |
string | No | ISO 8601 end datetime (null = no end, must be after starts_at) |
targets |
object[] | No | Product/collection/variant scoping (default: [] = all products) |
targets[].target_type |
string | Yes | product, collection, or variant |
targets[].target_id |
string | Yes | ID of the target resource |
Request
curl -X POST https://api.hydrajs.dev/v1/promotions \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Summer Sale",
"type": "percentage",
"value": 20,
"starts_at": "2026-08-01T00:00:00Z",
"ends_at": "2026-09-01T00:00:00Z",
"targets": [
{ "target_type": "collection", "target_id": "col_abc123" }
]
}'
Response 201
{
"data": {
"id": "promo_abc123def456ghij",
"name": "Summer Sale",
"type": "percentage",
"value": 20,
"status": "active",
"price_targets": ["base"],
"starts_at": "2026-08-01T00:00:00Z",
"ends_at": "2026-09-01T00:00:00Z",
"targets": [
{
"id": "ptgt_abc123def456ghij",
"target_type": "collection",
"target_id": "col_abc123",
"target_name": "Summer Collection"
}
],
"created_at": "2026-08-17T12:00:00Z",
"updated_at": "2026-08-17T12:00:00Z"
}
}
⚠Percentage limits
When type is percentage, value must be between 1 and 100. Values outside this range return a
400 validation error.
ℹCustomer group targeting
When price_targets contains a customer group ID (e.g. ["cg_abc123"]), the promotion only
applies when the customer is known and is a member of that group. This is resolved during cart
pricing when a customer_id is provided. Product listing endpoints show prices without
customer-group promotions applied.
Get a promotion
GET /v1/promotions/{id}
Returns a single promotion with its targets and resolved target names.
Request
curl https://api.hydrajs.dev/v1/promotions/promo_abc123def456ghij \
-H "Authorization: Bearer sk_live_YOUR_KEY"
Response 200
{
"data": {
"id": "promo_abc123def456ghij",
"name": "Summer Sale",
"type": "percentage",
"value": 20,
"status": "active",
"price_targets": ["base"],
"starts_at": "2026-08-01T00:00:00Z",
"ends_at": "2026-09-01T00:00:00Z",
"targets": [
{
"id": "ptgt_abc123def456ghij",
"target_type": "collection",
"target_id": "col_abc123",
"target_name": "Summer Collection"
}
],
"created_at": "2026-07-15T09:30:00Z",
"updated_at": "2026-07-15T09:30:00Z"
}
}
Update a promotion
PATCH /v1/promotions/{id}
Updates a promotion. All fields are optional — send only what changed. When targets is provided, it replaces the entire targets list.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | No | Promotion name (1–255 chars) |
type |
string | No | percentage or fixed_amount |
value |
integer | No | Discount value |
status |
string | No | active or disabled |
price_targets |
string[] | No | Price level or customer group to target (single value) |
starts_at |
string | No | ISO 8601 start datetime |
ends_at |
string | No | ISO 8601 end datetime (null to clear) |
targets |
object[] | No | Replaces all targets (empty array = all products) |
Request
curl -X PATCH https://api.hydrajs.dev/v1/promotions/promo_abc123def456ghij \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"value": 25, "targets": []}'
Response 200
{
"data": {
"id": "promo_abc123def456ghij",
"name": "Summer Sale",
"type": "percentage",
"value": 25,
"status": "active",
"price_targets": ["base"],
"starts_at": "2026-08-01T00:00:00Z",
"ends_at": "2026-09-01T00:00:00Z",
"targets": [],
"created_at": "2026-07-15T09:30:00Z",
"updated_at": "2026-08-17T14:00:00Z"
}
}
ℹReplace semantics
When targets is included in the update, the entire targets list is replaced. To add a target,
send the full list including existing targets. Omit targets entirely to leave them unchanged.
Delete a promotion
DELETE /v1/promotions/{id}
Soft-deletes a promotion by setting its status to archived and marking it as deleted. This action cannot be undone.
Request
curl -X DELETE https://api.hydrajs.dev/v1/promotions/promo_abc123def456ghij \
-H "Authorization: Bearer sk_live_YOUR_KEY"
Response 204
Empty body.
The promotion object
| Field | Type | Description |
|---|---|---|
id |
string | Unique ID (prefix: promo_) |
name |
string | Promotion name |
type |
string | Discount type: percentage or fixed_amount |
value |
integer | Discount value (percentage 1–100, or cents for fixed) |
status |
string | active, disabled, or archived |
price_targets |
string[] | Which price level or customer group this promotion targets. Contains a single value: a price tier key (base, *, or custom key) or a customer group ID (cg_...) |
starts_at |
string | ISO 8601 start datetime |
ends_at |
string | null | ISO 8601 end datetime, or null for no end |
targets |
object[] | Scoping targets (empty = applies to all products) |
targets[].id |
string | Target ID (prefix: ptgt_) |
targets[].target_type |
string | product, collection, or variant |
targets[].target_id |
string | ID of the target resource |
targets[].target_name |
string | null | Resolved name of the target (may be null if deleted) |
created_at |
string | ISO 8601 timestamp |
updated_at |
string | ISO 8601 timestamp |