Loyalty Challenges API
The Loyalty Challenges API allows you to manage loyalty programs and challenges in the Nilo platform. Loyalty challenges reward customers with points when they purchase specific products and reach a required amount.
Understanding Loyalty Challenges
Loyalty Challenges in Nilo are gamified promotions that reward customers:
- Challenge Structure
- Unique internal code for identification
- Title and description for display
- Points given as reward
- Required purchase amount to achieve the challenge
- Validity period (start and end dates)
- List of products that qualify for the challenge
Important Considerations
- Unique Codes: Each challenge requires a unique internal code (same as in your ERP)
- Points System: Define how many points customers earn when completing the challenge
- Required Amount: Set the minimum purchase amount needed to complete the challenge
- Product Scope: Specify which products count towards the challenge
- Date Validity: Challenges are only active within the start and end dates
Single Challenge Operations
Get Loyalty Challenge Details
/loyaltychallenge/{code}Retrieve detailed information about a specific loyalty challenge.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| code | string | Yes | Internal code of the loyalty challenge |
Response Example
{
"id": 1,
"title": "Summer Points Challenge",
"description": "Earn points on summer products",
"image": "https://example.com/challenge.jpg",
"internalCode": "CHALLENGE-001",
"pointsGiven": 100,
"requiredMoney": 500,
"enabled": true,
"startDate": "2025-06-01",
"endDate": "2025-08-31",
"products": [
{
"internalCode": "PROD-001"
},
{
"internalCode": "PROD-002"
}
]
}
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/loyaltychallenge/CHALLENGE-001",
{
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/loyaltychallenge/CHALLENGE-001"
headers = {
'Authorization': 'YOUR_AUTH_TOKEN',
'x-api-key': 'YOUR_API_KEY'
}
response = requests.get(url, headers=headers)
print(response.text)
List All Loyalty Challenges
/loyaltychallengeRetrieve a list of all loyalty challenges 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 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 or Update Loyalty Challenge
/loyaltychallengeCreate a new loyalty challenge or update an existing one.
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| title | string | Yes | Title of the challenge |
| internalCode | string | Yes | Unique identifier for the challenge |
| description | string | No | Description of the challenge |
| image | string | No | URL of the challenge image |
| pointsGiven | number | Yes | Points awarded when challenge is completed |
| requiredAmount | number | Yes | Minimum purchase amount to complete challenge |
| start | string | Yes | Start date (YYYY-MM-DD) |
| end | string | Yes | End date (YYYY-MM-DD) |
| enabled | boolean | Yes | Whether the challenge is active |
| products | array | Yes | Array of products that qualify for the challenge |
Request Body Example
{
"title": "Summer Points Challenge",
"internalCode": "CHALLENGE-001",
"description": "Earn 100 points when you spend $500 on summer products",
"image": "https://example.com/challenge.jpg",
"pointsGiven": 100,
"requiredAmount": 500,
"start": "2025-06-01",
"end": "2025-08-31",
"enabled": true,
"products": [
{
"internalCode": "PROD-001"
},
{
"internalCode": "PROD-002"
}
]
}
Example Usage
- Javascript
- Python
const headers = {
Authorization: "YOUR_AUTH_TOKEN",
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
};
const data = {
title: "Summer Points Challenge",
internalCode: "CHALLENGE-001",
description: "Earn 100 points when you spend $500 on summer products",
image: "https://example.com/challenge.jpg",
pointsGiven: 100,
requiredAmount: 500,
start: "2025-06-01",
end: "2025-08-31",
enabled: true,
products: [
{ internalCode: "PROD-001" },
{ internalCode: "PROD-002" },
],
};
fetch(
"https://tm0cs5kjs6.execute-api.us-east-1.amazonaws.com/dev/loyaltychallenge",
{
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://tm0cs5kjs6.execute-api.us-east-1.amazonaws.com/dev/loyaltychallenge"
headers = {
'Authorization': 'YOUR_AUTH_TOKEN',
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
}
data = {
"title": "Summer Points Challenge",
"internalCode": "CHALLENGE-001",
"description": "Earn 100 points when you spend $500 on summer products",
"image": "https://example.com/challenge.jpg",
"pointsGiven": 100,
"requiredAmount": 500,
"start": "2025-06-01",
"end": "2025-08-31",
"enabled": True,
"products": [
{"internalCode": "PROD-001"},
{"internalCode": "PROD-002"}
]
}
response = requests.put(url, headers=headers, json=data)
print(response.text)
Change Loyalty Challenge Status
/loyaltychallenge/{code}/statusEnable or disable a specific loyalty challenge.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| code | string | Yes | Internal code of the loyalty challenge |
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| enabled | boolean | Yes | New status of the challenge |
Request Body Example
{
"enabled": true
}
Example Usage
- Javascript
- Python
const headers = {
Authorization: "YOUR_AUTH_TOKEN",
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
};
const data = {
enabled: false,
};
fetch(
"https://tm0cs5kjs6.execute-api.us-east-1.amazonaws.com/dev/loyaltychallenge/CHALLENGE-001/status",
{
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://tm0cs5kjs6.execute-api.us-east-1.amazonaws.com/dev/loyaltychallenge/CHALLENGE-001/status"
headers = {
'Authorization': 'YOUR_AUTH_TOKEN',
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
}
data = {
"enabled": False
}
response = requests.put(url, headers=headers, json=data)
print(response.text)
Batch Operations
Batch Upsert Loyalty Challenges
/batch/loyalty-challengeThis endpoint allows you to create or update multiple loyalty challenges at once. The operation is processed asynchronously.
Use this endpoint when you need to:
- Set up multiple loyalty challenges simultaneously
- Synchronize challenges from your ERP or loyalty management system
- Bulk update challenge parameters (points, dates, products)
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| upsert | array | Yes | Array of loyalty challenge objects |
| upsert[].title | string | Yes | Challenge display title |
| upsert[].description | string | No | Challenge description |
| upsert[].image | string | No | Challenge image URL |
| upsert[].internalCode | string | Yes | Unique challenge code (same as in ERP) |
| upsert[].start | string | Yes | Start date (format: YYYY-MM-DD) |
| upsert[].end | string | Yes | End date (format: YYYY-MM-DD) |
| upsert[].pointsGiven | number | Yes | Points awarded when completing the challenge |
| upsert[].requiredAmount | number | Yes | Minimum purchase amount required to complete |
| upsert[].enabled | boolean | Yes | Whether the challenge is active |
| upsert[].products | array | Yes | Products that qualify for the challenge |
| upsert[].loyaltyGroupInternalCodes | array | No | Internal codes of loyalty groups to associate |
Product Object Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| internalCode | string | Yes | Product internal code |
| units | number | Yes | Required units of this product |
Request Body Example
{
"upsert": [
{
"title": "Buy 10 Sodas Challenge",
"description": "Purchase 10 units of any soda to earn 500 points",
"internalCode": "CHALLENGE-001",
"start": "2025-12-01",
"end": "2025-12-31",
"pointsGiven": 500,
"requiredAmount": 10,
"enabled": true,
"products": [
{ "internalCode": "PROD-001", "units": 5 },
{ "internalCode": "PROD-002", "units": 5 }
],
"loyaltyGroupInternalCodes": ["GROUP-GOLD", "GROUP-SILVER"]
},
{
"title": "Snack Lover Challenge",
"internalCode": "CHALLENGE-002",
"start": "2025-12-01",
"end": "2026-01-31",
"pointsGiven": 200,
"requiredAmount": 5,
"enabled": true,
"products": [
{ "internalCode": "SNACK-001", "units": 5 }
]
}
]
}
Response Codes
| Code | Description |
|---|---|
| 202 | Request accepted, processing initiated |
| 400 | Bad request - Invalid parameters |
| 403 | Forbidden - Insufficient permissions |
Response Example
{
"code": 202,
"batchIds": {},
"message": "Operation in processing"
}
Example Usage
- Javascript
- Python
const headers = {
Authorization: "YOUR_AUTH_TOKEN",
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
};
const data = {
upsert: [
{
title: "Buy 10 Sodas Challenge",
internalCode: "CHALLENGE-001",
start: "2025-12-01",
end: "2025-12-31",
pointsGiven: 500,
requiredAmount: 10,
enabled: true,
products: [
{ internalCode: "PROD-001", units: 5 },
{ internalCode: "PROD-002", units: 5 },
],
loyaltyGroupInternalCodes: ["GROUP-GOLD"],
},
],
};
fetch(
"https://tm0cs5kjs6.execute-api.us-east-1.amazonaws.com/dev/batch/loyalty-challenge",
{
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://tm0cs5kjs6.execute-api.us-east-1.amazonaws.com/dev/batch/loyalty-challenge"
headers = {
'Authorization': 'YOUR_AUTH_TOKEN',
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
}
data = {
"upsert": [
{
"title": "Buy 10 Sodas Challenge",
"internalCode": "CHALLENGE-001",
"start": "2025-12-01",
"end": "2025-12-31",
"pointsGiven": 500,
"requiredAmount": 10,
"enabled": True,
"products": [
{"internalCode": "PROD-001", "units": 5},
{"internalCode": "PROD-002", "units": 5}
],
"loyaltyGroupInternalCodes": ["GROUP-GOLD"]
}
]
}
response = requests.post(url, headers=headers, json=data)
print(response.text)
Error Codes
When an operation fails, the API returns a structured error response:
{
"code": 404,
"message": "LOYALTY_CHALLENGE_NOT_FOUND",
"object": {
"statusCode": 404,
"code": "LOYALTY_CHALLENGE_NOT_FOUND",
"message": "Loyalty challenge not found",
"entity": "loyaltyChallenge",
"entityCode": "LC-001",
"timestamp": "2026-05-18T15:16:47.000Z"
}
}
The object field provides additional context about the error:
| Field | Description |
|---|---|
statusCode | HTTP status code |
code | Error code (same as top-level message) |
message | Human-readable error description |
entity | Entity type that caused the error |
entityCode | The internalCode of the entity involved |
timestamp | When the error occurred (ISO 8601) |
404 — Not Found
| Error Code | Description |
|---|---|
LOYALTY_CHALLENGE_NOT_FOUND | The loyalty challenge does not exist |
PRODUCT_CODE_NOT_FOUND | One of the product codes in the challenge does not exist |
LOYALTY_GROUP_NOT_FOUND | The loyalty group to add/remove does not exist |
400 — Bad Request
| Error Code | Description |
|---|---|
START_DATE_AFTER_END_DATE | The start date is after the end date |
POINTS_GIVEN_IS_NEGATIVE | The points given value must be positive |
POINTS_GIVEN_IS_DECIMAL | The points given value must be an integer |
REQUIRED_AMOUNT_IS_NOT_POSITIVE | The required amount must be greater than zero |
DUPLICATE_PRODUCT_CODE | The same product code appears more than once in the request |
409 — Conflict
| Error Code | Description |
|---|---|
INTERNAL_CODE_ALREADY_EXIST | A challenge with the same internal code already exists |
LOYALTY_GROUP_ALREADY_IN_LOYALTY_CHALLENGE | The loyalty group is already associated with this challenge |
LOYALTY_GROUP_HAS_CONFLICTS | The loyalty group has conflicting assignments with other challenges |
LOYALTY_GROUP_NOT_IN_LOYALTY_CHALLENGE | The loyalty group is not associated with this challenge (when trying to remove) |
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/loyaltychallenge.read - For writing operations:
supplier/loyaltychallenge.write - For batch operations:
supplier/loyaltychallenge.bulkwrite