Promotion Management API
Overview
The Promotion Management API provides a comprehensive set of endpoints for managing promotions in the Nilo platform. This API allows you to create, update, and manage different types of promotions including simple discounts, multiple discounts, individual bonuses, and crossed bonuses.
Understanding Promotions
Promotion Structure
- Internal Code: Unique identifier for the promotion (same as in your ERP)
- Name: Descriptive name for the promotion
- Type: Type of promotion (DISCOUNT_SIMPLE, DISCOUNT_MULTIPLE, BONUS_INDIVIDUAL, BONUS_CROSSED)
- Status: Enabled/disabled state of the promotion
- Validity Period: Start and end dates for the promotion
- Tiers: Conditions for discounts or bonuses (quantity-based or amount-based)
- Products: Products included in the promotion
- Groupers: Promotion groupers that determine which stores see the promotion
Promotion Types Mapping
| Promotion Type | Nilo API Type | Endpoint |
|---|---|---|
| Direct Bonus (same product) | BONUS_INDIVIDUAL | PUT /promotion/bonus/individual |
| Crossed Bonus (different product) | BONUS_CROSSED | PUT /promotion/bonus/crossed |
| Group Discount (product combination) | DISCOUNT_MULTIPLE | PUT /promotion/discount/multiple |
| Tiered Simple Discount | DISCOUNT_SIMPLE | PUT /promotion/discount/simple |
| Combos with discount | DISCOUNT_MULTIPLE | PUT /promotion/discount/multiple |
| Combos with bonus | BONUS_CROSSED | PUT /promotion/bonus/crossed |
Important Considerations
The API defines certain fields as mutually exclusive:
- Quantity vs Amount condition: Don't send
discountTiersData/bonusTierDataanddiscountTiersDataCash/bonusTierDataCashsimultaneously - Discount type: Specify
discountPercentageORdiscountAmount, not both
Sending both fields will result in an error.
-
Tier Types:
- Quantity-based (
discountTiersData/bonusTierData): Discount applies based on quantity purchased (e.g., buy 5+ units get 10% off) - Amount-based (
discountTiersDataCash/bonusTierDataCash): Discount applies based on purchase amount (e.g., spend $100+ get 10% off)
- Quantity-based (
-
Discount Configuration:
- Can be percentage-based (
discountPercentage) or fixed amount (discountAmount) - Cannot mix percentage and fixed amount in the same tier
- Multiple tiers can be configured with different thresholds
- Can be percentage-based (
-
Image Management:
- The
imagefield expects a public and accessible URL - Nilo will download, store, and distribute through CDN
- Use high-quality images - optimized versions are auto-generated for different devices
- The
-
Date Handling:
- All dates must be in YYYY-MM-DD format
- Both start and end dates are required
- End date must be after start date
Single Promotion Operations
Get Promotion Details
/promotion/{code}Retrieve detailed information about a specific promotion.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| code | string | Yes | Internal code of the promotion |
Response Example
{
"name": "Summer Sale",
"internalCode": "SUMMER2023",
"title": "Summer Sale",
"enabled": true,
"description": "Summer Sale 20%",
"image": "https://image.jpg",
"start": "2023-06-01",
"end": "2023-08-31",
"type": "DISCOUNT_SIMPLE",
"products": [
{
"internalCode": "PROD123",
"boxRatio": 1
}
],
"discountTiersData": [
{
"min": 1,
"max": 2,
"discountPercentage": 20
}
]
}
Example Usage
- Javascript
- Python
const headers = {
Authorization: "YOUR_AUTH_TOKEN",
"x-api-key": "YOUR_API_KEY",
};
fetch(
"https://tm0cs5kjs6.execute-api.us-east-1.amazonaws.com/dev/promotion/SUMMER2023",
{
method: "GET",
headers: headers,
}
)
.then((response) => response.json())
.then((result) => console.log(result))
.catch((error) => console.log("error", error));
import requests
url = "https://tm0cs5kjs6.execute-api.us-east-1.amazonaws.com/dev/promotion/SUMMER2023"
headers = {
'Authorization': 'YOUR_AUTH_TOKEN',
'x-api-key': 'YOUR_API_KEY'
}
response = requests.get(url, headers=headers)
print(response.text)
List All Promotions
/promotionRetrieve a list of all promotions with pagination and filtering support.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| take | number | No | Number of items per page (default: 50, max: 50) |
| page | string | No | Page number (default: 1) |
| cursor | string | No | Cursor for pagination. First call should pass 0, subsequent calls use the cursor from the last item of the previous response |
| enabled | boolean | No | Filter by enabled status |
| from | string | No | Start date filter (YYYY-MM-DD) |
| to | string | No | End date filter (YYYY-MM-DD) |
Create/Update Simple Discount Promotion
/promotion/discount/simpleCreate or update a simple discount promotion for a single product with tiered discounts.
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Name of the promotion |
| internalCode | string | Yes | Unique identifier for the promotion (same as in ERP) |
| start | string | Yes | Start date (YYYY-MM-DD) |
| end | string | Yes | End date (YYYY-MM-DD) |
| products | object | Yes | Product included in the promotion |
| discountTiersData | array | No* | Quantity-based discount tiers (min, max, discountPercentage OR discountAmount) |
| discountTiersDataCash | array | No* | Amount-based discount tiers (cashMinAmount, cashMaxAmount, discountPercentage OR discountAmount) |
| enabled | boolean | Yes | Whether the promotion is active |
| promotionGrouperCodes | array | No | Array of promotion grouper codes |
| recommendationThreshold | number | No | Threshold value for the promotion to be suggested to users |
*Either discountTiersData OR discountTiersDataCash must be provided, not both.
discountTiersData (quantity-based):
| Field | Type | Required | Description |
|---|---|---|---|
| min | integer | Yes | Minimum quantity to qualify |
| max | integer | No | Maximum quantity for this tier |
| discountPercentage | number | No* | Percentage discount (e.g., 10.5 for 10.5%) |
| discountAmount | number | No* | Fixed amount discount |
discountTiersDataCash (amount-based):
| Field | Type | Required | Description |
|---|---|---|---|
| cashMinAmount | number | Yes | Minimum purchase amount to qualify |
| cashMaxAmount | number | No | Maximum amount for this tier |
| discountPercentage | number | No* | Percentage discount |
| discountAmount | number | No* | Fixed amount discount |
*Use discountPercentage OR discountAmount, not both.
Request Body Example (Quantity-based)
{
"name": "Summer Sale",
"internalCode": "SUMMER2023",
"start": "2025-06-01",
"end": "2025-08-31",
"products": {
"internalCode": "PROD123",
"boxRatio": 1
},
"discountTiersData": [
{
"min": 1,
"max": 5,
"discountPercentage": 10
},
{
"min": 6,
"max": 10,
"discountPercentage": 15
},
{
"min": 11,
"discountPercentage": 20
}
],
"enabled": true,
"promotionGrouperCodes": ["GROUP1", "GROUP2"],
"recommendationThreshold": 5
}
Request Body Example (Amount-based)
{
"name": "Spend & Save",
"internalCode": "SPEND2025",
"start": "2025-06-01",
"end": "2025-08-31",
"products": {
"internalCode": "PROD123",
"boxRatio": 1
},
"discountTiersDataCash": [
{
"cashMinAmount": 100,
"cashMaxAmount": 500,
"discountPercentage": 5
},
{
"cashMinAmount": 500,
"discountPercentage": 10
}
],
"enabled": true,
"promotionGrouperCodes": ["GROUP1"]
}
Example Usage for Simple Discount Promotion
- Javascript
- Python
const headers = {
Authorization: "YOUR_AUTH_TOKEN",
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
};
const data = {
name: "Summer Sale",
internalCode: "SUMMER2023",
start: "2023-06-01",
end: "2023-08-31",
products: {
internalCode: "PROD123",
boxRatio: 1,
},
discountTiersData: [
{
min: 1,
max: 2,
discountPercentage: 10.5,
},
],
enabled: true,
promotionGrouperCodes: ["GROUP1", "GROUP2"],
};
fetch("https://api.nilo.com/promotion/discount/simple", {
method: "PUT",
headers: headers,
body: JSON.stringify(data),
})
.then((response) => response.json())
.then((result) => console.log(result))
.catch((error) => console.log("error", error));
import requests
url = "https://api.nilo.com/promotion/discount/simple"
headers = {
'Authorization': 'YOUR_AUTH_TOKEN',
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
}
data = {
"name": "Summer Sale",
"internalCode": "SUMMER2023",
"start": "2023-06-01",
"end": "2023-08-31",
"products": {
"internalCode": "PROD123",
"boxRatio": 1
},
"discountTiersData": [
{
"min": 1,
"max": 2,
"discountPercentage": 10.5
}
],
"enabled": True,
"promotionGrouperCodes": ["GROUP1", "GROUP2"]
}
response = requests.put(url, headers=headers, json=data)
print(response.text)
Create/Update Multiple Discount Promotion
/promotion/discount/multipleCreate or update a promotion with multiple discount tiers.
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Name of the promotion |
| internalCode | string | Yes | Unique identifier for the promotion |
| title | string | No | Display title for the promotion |
| description | string | No | Detailed description |
| image | string | No | URL of promotion image |
| start | string | Yes | Start date (YYYY-MM-DD) |
| end | string | Yes | End date (YYYY-MM-DD) |
| products | array | Yes | Array of products in promotion |
| discountTiersData | array | Yes | Discount tiers configuration |
| enabled | boolean | Yes | Whether the promotion is active |
Request Body Example
{
"name": "Bulk Purchase Discount",
"internalCode": "BULK2023",
"title": "Buy More, Save More",
"description": "Progressive discounts on bulk purchases",
"image": "https://example.com/promo.jpg",
"start": "2023-06-01",
"end": "2023-08-31",
"products": [
{
"internalCode": "PROD123",
"boxRatio": 1
},
{
"internalCode": "PROD124",
"boxRatio": 1
}
],
"discountTiersData": [
{
"min": 1,
"max": 5,
"discountPercentage": 10
},
{
"min": 6,
"max": 10,
"discountPercentage": 15
}
],
"enabled": true
}
Example Usage for Multiple Discount Promotion
- Javascript
- Python
const headers = {
Authorization: "YOUR_AUTH_TOKEN",
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
};
const data = {
name: "Bulk Purchase Discount",
internalCode: "BULK2023",
title: "Buy More, Save More",
description: "Progressive discounts on bulk purchases",
image: "https://example.com/promo.jpg",
start: "2023-06-01",
end: "2023-08-31",
products: [
{
internalCode: "PROD123",
boxRatio: 1,
},
{
internalCode: "PROD124",
boxRatio: 1,
},
],
discountTiersData: [
{
min: 1,
max: 5,
discountPercentage: 10,
},
{
min: 6,
max: 10,
discountPercentage: 15,
},
],
enabled: true,
};
fetch("https://api.nilo.com/promotion/discount/multiple", {
method: "PUT",
headers: headers,
body: JSON.stringify(data),
})
.then((response) => response.json())
.then((result) => console.log(result))
.catch((error) => console.log("error", error));
import requests
url = "https://api.nilo.com/promotion/discount/multiple"
headers = {
'Authorization': 'YOUR_AUTH_TOKEN',
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
}
data = {
"name": "Bulk Purchase Discount",
"internalCode": "BULK2023",
"title": "Buy More, Save More",
"description": "Progressive discounts on bulk purchases",
"image": "https://example.com/promo.jpg",
"start": "2023-06-01",
"end": "2023-08-31",
"products": [
{
"internalCode": "PROD123",
"boxRatio": 1
},
{
"internalCode": "PROD124",
"boxRatio": 1
}
],
"discountTiersData": [
{
"min": 1,
"max": 5,
"discountPercentage": 10
},
{
"min": 6,
"max": 10,
"discountPercentage": 15
}
],
"enabled": True
}
response = requests.put(url, headers=headers, json=data)
print(response.text)
Create/Update Individual Bonus Promotion
/promotion/bonus/individualCreate or update a buy X get Y promotion for the same product.
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Name of the promotion |
| internalCode | string | Yes | Unique identifier for the promotion |
| start | string | Yes | Start date (YYYY-MM-DD) |
| end | string | Yes | End date (YYYY-MM-DD) |
| products | object | Yes | Product configuration |
| bonusTierData | object | Yes | Bonus configuration |
| enabled | boolean | Yes | Whether the promotion is active |
Request Body Example
{
"name": "Buy 2 Get 1 Free",
"internalCode": "B2G1FREE",
"start": "2023-06-01",
"end": "2023-08-31",
"products": {
"internalCode": "PROD123",
"boxRatio": 1
},
"bonusTierData": {
"quantityRequired": 2,
"quantityGiven": 1,
"units": 1
},
"enabled": true
}
Example Usage for Individual Bonus Promotion
- Javascript
- Python
const headers = {
Authorization: "YOUR_AUTH_TOKEN",
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
};
const data = {
name: "Buy 2 Get 1 Free",
internalCode: "B2G1FREE",
start: "2023-06-01",
end: "2023-08-31",
products: {
internalCode: "PROD123",
boxRatio: 1,
},
bonusTierData: {
quantityRequired: 2,
quantityGiven: 1,
units: 1,
},
enabled: true,
};
fetch("https://api.nilo.com/promotion/bonus/individual", {
method: "PUT",
headers: headers,
body: JSON.stringify(data),
})
.then((response) => response.json())
.then((result) => console.log(result))
.catch((error) => console.log("error", error));
import requests
url = "https://api.nilo.com/promotion/bonus/individual"
headers = {
'Authorization': 'YOUR_AUTH_TOKEN',
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
}
data = {
"name": "Buy 2 Get 1 Free",
"internalCode": "B2G1FREE",
"start": "2023-06-01",
"end": "2023-08-31",
"products": {
"internalCode": "PROD123",
"boxRatio": 1
},
"bonusTierData": {
"quantityRequired": 2,
"quantityGiven": 1,
"units": 1
},
"enabled": True
}
response = requests.put(url, headers=headers, json=data)
print(response.text)
Create/Update Crossed Bonus Promotion
/promotion/bonus/crossedCreate or update a promotion where buying one product gives a bonus of a different product.
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Name of the promotion |
| internalCode | string | Yes | Unique identifier for the promotion |
| title | string | No | Display title for the promotion |
| description | string | No | Detailed description |
| image | string | No | URL of promotion image |
| start | string | Yes | Start date (YYYY-MM-DD) |
| end | string | Yes | End date (YYYY-MM-DD) |
| products | array | Yes | Products that trigger the bonus |
| bonusTierData | object | Yes | Bonus product configuration |
| enabled | boolean | Yes | Whether the promotion is active |
Request Body Example
{
"name": "Buy X Get Y Free",
"internalCode": "CROSSPROMO",
"title": "Special Cross Promotion",
"description": "Buy Product A, Get Product B Free",
"image": "https://example.com/cross-promo.jpg",
"start": "2023-06-01",
"end": "2023-08-31",
"products": [
{
"internalCode": "PRODA",
"boxRatio": 1
}
],
"bonusTierData": {
"quantityRequired": 2,
"quantityGiven": 1,
"productInternalCode": "PRODB",
"units": 1
},
"enabled": true
}
Example Usage for Crossed Bonus Promotion
- Javascript
- Python
const headers = {
Authorization: "YOUR_AUTH_TOKEN",
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
};
const data = {
name: "Buy X Get Y Free",
internalCode: "CROSSPROMO",
title: "Special Cross Promotion",
description: "Buy Product A, Get Product B Free",
image: "https://example.com/cross-promo.jpg",
start: "2023-06-01",
end: "2023-08-31",
products: [
{
internalCode: "PRODA",
boxRatio: 1,
},
],
bonusTierData: {
quantityRequired: 2,
quantityGiven: 1,
productInternalCode: "PRODB",
units: 1,
},
enabled: true,
};
fetch("https://api.nilo.com/promotion/bonus/crossed", {
method: "PUT",
headers: headers,
body: JSON.stringify(data),
})
.then((response) => response.json())
.then((result) => console.log(result))
.catch((error) => console.log("error", error));
import requests
url = "https://api.nilo.com/promotion/bonus/crossed"
headers = {
'Authorization': 'YOUR_AUTH_TOKEN',
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
}
data = {
"name": "Buy X Get Y Free",
"internalCode": "CROSSPROMO",
"title": "Special Cross Promotion",
"description": "Buy Product A, Get Product B Free",
"image": "https://example.com/cross-promo.jpg",
"start": "2023-06-01",
"end": "2023-08-31",
"products": [
{
"internalCode": "PRODA",
"boxRatio": 1
}
],
"bonusTierData": {
"quantityRequired": 2,
"quantityGiven": 1,
"productInternalCode": "PRODB",
"units": 1
},
"enabled": True
}
response = requests.put(url, headers=headers, json=data)
print(response.text)
Change Promotion Status
/promotion/{code}/statusEnable or disable a specific promotion.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| code | string | Yes | Internal code of the promotion |
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| enabled | boolean | Yes | New status for the promotion |
Request Body Example
{
"enabled": true
}
Batch Operations
Batch Update Promotions
/batch/promotionUpdate multiple promotions in a single operation.
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| upsert | object | No | Contains promotions to create or update |
| remove | object | No | Contains promotions to remove |
Request Body Example
{
"upsert": {
"discount": {
"simple": [
{
"name": "Simple Discount 1",
"internalCode": "SD1",
"start": "2023-06-01",
"end": "2023-08-31",
"products": {
"internalCode": "PROD1",
"boxRatio": 1
},
"discountTiersData": [
{
"min": 1,
"discountPercentage": 10
}
],
"enabled": true
}
],
"multiple": []
},
"bonus": {
"individual": [],
"crossed": []
}
}
}
Example Usage for Batch Operations
- Javascript
- Python
const headers = {
Authorization: "YOUR_AUTH_TOKEN",
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
};
const data = {
upsert: {
discount: {
simple: [
{
name: "Simple Discount 1",
internalCode: "SD1",
start: "2023-06-01",
end: "2023-08-31",
products: {
internalCode: "PROD1",
boxRatio: 1,
},
discountTiersData: [
{
min: 1,
discountPercentage: 10,
},
],
enabled: true,
},
],
multiple: [],
},
bonus: {
individual: [],
crossed: [],
},
},
};
fetch("https://api.nilo.com/batch/promotion", {
method: "POST",
headers: headers,
body: JSON.stringify(data),
})
.then((response) => response.json())
.then((result) => console.log(result))
.catch((error) => console.log("error", error));
import requests
url = "https://api.nilo.com/batch/promotion"
headers = {
'Authorization': 'YOUR_AUTH_TOKEN',
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
}
data = {
"upsert": {
"discount": {
"simple": [
{
"name": "Simple Discount 1",
"internalCode": "SD1",
"start": "2023-06-01",
"end": "2023-08-31",
"products": {
"internalCode": "PROD1",
"boxRatio": 1
},
"discountTiersData": [
{
"min": 1,
"discountPercentage": 10
}
],
"enabled": True
}
],
"multiple": []
},
"bonus": {
"individual": [],
"crossed": []
}
}
}
response = requests.post(url, headers=headers, json=data)
print(response.text)
Batch Update Promotion Groupers
/batch/promotion/update/grouperAdd or remove promotion groupers from promotions in bulk. This is useful for changing which stores can see specific promotions.
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| add | object | No | Contains groups to add to promotions |
| remove | object | No | Contains groups to remove from promotions |
groups array items:
| Parameter | Type | Required | Description |
|---|---|---|---|
| internalCode | string | Yes | Internal code of the promotion |
| groupInternalCode | string | Yes | Internal code of the grouper |
Request Body Example
{
"add": {
"groups": [
{
"internalCode": "PROMO123",
"groupInternalCode": "GROUP1"
},
{
"internalCode": "PROMO123",
"groupInternalCode": "GROUP2"
}
]
},
"remove": {
"groups": [
{
"internalCode": "PROMO456",
"groupInternalCode": "GROUP3"
}
]
}
}
Response Codes
| Code | Description |
|---|---|
| 202 | Request accepted, processing initiated |
| 402 | Bad request |
Security
Authentication
All endpoints require two types of authentication:
- API Key in header:
x-api-key - Authorization token in header:
Authorization
Required Permissions
- For reading operations:
supplier/promotion.read - For writing operations:
supplier/promotion.write - For batch operations:
supplier/promotion.bulkwrite