This document outlines the procedure for making API calls to retrieve product quantity discount data from https://easycms.fi/public_api/get_products_qty_discount/.
The pid (Product ID) parameter is MANDATORY for this endpoint. You must provide a valid product ID to retrieve quantity discount tiers.
Fetch quantity discount tiers for a specific product. Quantity discounts allow you to offer tiered pricing based on the quantity purchased.
https://easycms.fi/public_api/get_products_qty_discount/TOKEN (api_key): Your unique API key for authentication. How to Create API Credentials.username: Your login username. password: Your login password. account: Your specific account ID. pid: Product ID (MANDATORY) - The ID of the product to retrieve quantity discounts for. Must be an integer.start - Specify the starting point of the row from which to begin fetching data (default: 0).limit - Control the number of records returned in a single request (default: 50, max: 50).
# Get all quantity discounts for a product
curl -X POST 'https://easycms.fi/public_api/get_products_qty_discount' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&pid=12345'
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://easycms.fi/public_api/get_products_qty_discount",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'username' => 'USERNAME',
'password' => 'PASSWORD',
'account' => 'ACCOUNT_ID',
'pid' => 12345
]),
CURLOPT_HTTPHEADER => array("Authorization1: TOKEN"),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
import requests
url = "https://easycms.fi/public_api/get_products_qty_discount"
headers = {"Authorization1": "TOKEN"}
payload = {
'username': 'USERNAME',
'password': 'PASSWORD',
'account': 'ACCOUNT_ID',
'pid': 12345
}
response = requests.post(url, headers=headers, data=payload)
print(response.text)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://easycms.fi/public_api/get_products_qty_discount"))
.headers("Authorization1", "TOKEN")
.POST(HttpRequest.BodyPublishers.ofString(
"username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&pid=12345"))
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
const https = require('https');
const data = new URLSearchParams({
username: 'USERNAME',
password: 'PASSWORD',
account: 'ACCOUNT_ID',
pid: 12345
}).toString();
const options = {
hostname: 'easycms.fi',
path: '/public_api/get_products_qty_discount',
method: 'POST',
headers: {
'Authorization1': 'TOKEN',
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': data.length
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => { console.log(data); });
});
req.on('error', (e) => { console.error(e); });
req.write(data);
req.end();
import React, { useEffect, useState } from 'react';
function App() {
const [discountData, setDiscountData] = useState('');
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('https://easycms.fi/public_api/get_products_qty_discount', {
method: 'POST',
headers: {'Authorization1': 'TOKEN', 'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
username: 'USERNAME',
password: 'PASSWORD',
account: 'ACCOUNT_ID',
pid: 12345
}).toString()
});
const data = await response.text();
setDiscountData(data);
} catch (error) {
console.error(error);
}
};
fetchData();
}, []);
return ({discountData});
}
export default App;
import okhttp3.OkHttpClient
import okhttp3.FormBody
import okhttp3.Request
fun main() {
val client = OkHttpClient()
val formBody = FormBody.Builder()
.add("username", "USERNAME")
.add("password", "PASSWORD")
.add("account", "ACCOUNT_ID")
.add("pid", "12345")
.build()
val request = Request.Builder()
.url("https://easycms.fi/public_api/get_products_qty_discount")
.post(formBody)
.addHeader("Authorization1", "TOKEN")
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
println(response.body?.string())
}
}
using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var token = "TOKEN";
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair("username", "USERNAME"),
new KeyValuePair("password", "PASSWORD"),
new KeyValuePair("account", "ACCOUNT_ID"),
new KeyValuePair("pid", "12345")
});
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("Authorization1", token);
var response = await httpClient.PostAsync("https://easycms.fi/public_api/get_products_qty_discount", content);
if (response.IsSuccessStatusCode)
{
var responseData = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseData);
}
else
{
Console.WriteLine($"Error: {response.StatusCode}");
}
}
}
}
When you make a request to the endpoint, you receive a JSON response containing various keys and values. Here's an explanation of the response keys and their meanings:
- `start`: This represents the starting index for the data. In this case, it's set to 0, indicating that the data starts from the first item.
- `limit`: The maximum number of items returned in the response. In this example, the limit is set to 50, meaning that the response will include up to 50 items.
- `count`: The number of items included in the current response. In this case, there are 4 items in the response.
- `total_count`: The total count of items available in the dataset. In this response, there is a total of 4 items available.
- `pid`: The product ID that was queried.
- `id`: The unique identifier (UUID) for the discount tier record.
- `pid`: The product ID this discount tier belongs to.
- `crp_id`: The product reference ID from the products table.
- `min_qty`: The minimum quantity required to qualify for this discount.
- `discount`: The discount amount (interpretation depends on discount_type).
- `discount_type`: The type of discount. Only three values are ever returned by this endpoint: `0` = percentage, `1` = gross total line, `3` = gross per product. (Value `2` = "none" is an admin-UI sentinel for empty rows and is never stored in the database, so it never appears here.)
- `discount_type_label`: Human-readable label for the discount type ("percentage", "gross_total_line", "none", or "gross_per_product").
- `datenew`: The date and time when this discount tier was created (YYYY-MM-DD HH:MM:SS format).
These key-value pairs provide comprehensive information about the quantity discount tiers for a product and can be used for implementing tiered pricing in your application.
{
"INFO": {
"start": 0,
"limit": 50,
"count": 4,
"total_count": 4,
"pid": 12345
},
"OUTPUT": [
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"pid": 12345,
"crp_id": "PROD-001",
"min_qty": 10,
"discount": 5.00,
"discount_type": 0,
"discount_type_label": "percentage",
"datenew": "2024-01-15 10:30:00"
},
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"pid": 12345,
"crp_id": "PROD-001",
"min_qty": 25,
"discount": 10.00,
"discount_type": 0,
"discount_type_label": "percentage",
"datenew": "2024-01-15 10:30:00"
},
{
"id": "550e8400-e29b-41d4-a716-446655440003",
"pid": 12345,
"crp_id": "PROD-001",
"min_qty": 50,
"discount": 85.00,
"discount_type": 1,
"discount_type_label": "gross_total_line",
"datenew": "2024-01-15 10:30:00"
},
{
"id": "550e8400-e29b-41d4-a716-446655440004",
"pid": 12345,
"crp_id": "PROD-001",
"min_qty": 100,
"discount": 12.50,
"discount_type": 3,
"discount_type_label": "gross_per_product",
"datenew": "2024-01-15 10:30:00"
}
]
}
| Value | Label | Description |
|---|---|---|
| 0 | percentage | Discount is a percentage off the original price (e.g., 5 = 5% off) |
| 1 | gross_total_line | Discount represents the total gross price for ALL min_qty units (e.g., 85.00 = €85.00 total for 50 units) |
| 2 | none | No discount type selected (placeholder, not stored in DB) |
| 3 | gross_per_product | Discount represents the gross price per single unit (e.g., 12.50 = €12.50 per unit) |
Here are the possible error messages and their meanings:
| Error Code | HTTP Status | Description |
|---|---|---|
pid_parameter_is_required |
400 | The pid parameter is required |
pid_must_be_a_valid_positive_integer |
400 | The pid must be a valid integer |
product_not_found |
404 | The product with the specified pid does not exist |
UN-AUTHORIZED |
401 | Incorrect username or password |
this_account_does_not_exist_or_your_credentials_do_not_match_this_account |
401 | The account doesn't exist or mismatched credentials |
Maximum query size is 50 rows per query |
400 | Exceeded maximum limit of 50 rows per query |
{
"OUTPUT": {
"response_type": "error",
"message": "pid_parameter_is_required"
}
}
When a product exists but has no quantity discounts configured:
{
"INFO": {
"start": 0,
"limit": 50,
"count": 0,
"total_count": 0,
"pid": 12345
},
"OUTPUT": []
}
Use the quantity discount tiers to calculate the final price for a given quantity:
// Example in JavaScript
function calculateFinalPrice(basePrice, quantity, discountTiers) {
// Sort tiers by min_qty descending to find the applicable discount
const sortedTiers = discountTiers.sort((a, b) => b.min_qty - a.min_qty);
for (const tier of sortedTiers) {
if (quantity >= tier.min_qty) {
if (tier.discount_type === 0) {
// Percentage discount
return basePrice * (1 - tier.discount / 100);
} else if (tier.discount_type === 1) {
// Gross total line — discount is the total price for ALL min_qty units
const pricePerUnit = tier.discount / tier.min_qty;
return pricePerUnit * quantity;
} else if (tier.discount_type === 3) {
// Gross per product — discount is the price per single unit
return tier.discount * quantity;
}
}
}
// No discount applies
return basePrice * quantity;
}
// Usage
const basePrice = 100.00;
const quantity = 30;
const discountTiers = response.OUTPUT;
const finalPrice = calculateFinalPrice(basePrice, quantity, discountTiers);
console.log(`Final price for ${quantity} units: €${finalPrice.toFixed(2)}`);
Show customers the available discounts for larger quantities:
<table>
<thead>
<tr>
<th>Quantity</th>
<th>Discount</th>
</tr>
</thead>
<tbody>
<!-- Loop through OUTPUT array -->
<tr>
<td>10+</td>
<td>5% off</td>
</tr>
<tr>
<td>25+</td>
<td>10% off</td>
</tr>
<tr>
<td>50+</td>
<td>€85.00 total (gross total line)</td>
</tr>
<tr>
<td>100+</td>
<td>€12.50 each (gross per product)</td>
</tr>
</tbody>
</table>
This document outlines the procedure for making API calls to retrieve product quantity discount data from https://easycms.fi/public_api/get_products_qty_discount/.
The pid (Product ID) parameter is MANDATORY for this endpoint. You must provide a valid product ID to retrieve quantity discount tiers.
Fetch quantity discount tiers for a specific product. Quantity discounts allow you to offer tiered pricing based on the quantity purchased.
https://easycms.fi/public_api/get_products_qty_discount/TOKEN (api_key): Your unique API key for authentication. How to Create API Credentials.username: Your login username. password: Your login password. account: Your specific account ID. pid: Product ID (MANDATORY) - The ID of the product to retrieve quantity discounts for. Must be an integer.start - Specify the starting point of the row from which to begin fetching data (default: 0).limit - Control the number of records returned in a single request (default: 50, max: 50).
# Get all quantity discounts for a product
curl -X POST 'https://easycms.fi/public_api/get_products_qty_discount' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&pid=12345'
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://easycms.fi/public_api/get_products_qty_discount",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'username' => 'USERNAME',
'password' => 'PASSWORD',
'account' => 'ACCOUNT_ID',
'pid' => 12345
]),
CURLOPT_HTTPHEADER => array("Authorization1: TOKEN"),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
import requests
url = "https://easycms.fi/public_api/get_products_qty_discount"
headers = {"Authorization1": "TOKEN"}
payload = {
'username': 'USERNAME',
'password': 'PASSWORD',
'account': 'ACCOUNT_ID',
'pid': 12345
}
response = requests.post(url, headers=headers, data=payload)
print(response.text)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://easycms.fi/public_api/get_products_qty_discount"))
.headers("Authorization1", "TOKEN")
.POST(HttpRequest.BodyPublishers.ofString(
"username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&pid=12345"))
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
const https = require('https');
const data = new URLSearchParams({
username: 'USERNAME',
password: 'PASSWORD',
account: 'ACCOUNT_ID',
pid: 12345
}).toString();
const options = {
hostname: 'easycms.fi',
path: '/public_api/get_products_qty_discount',
method: 'POST',
headers: {
'Authorization1': 'TOKEN',
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': data.length
}
};
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => { console.log(data); });
});
req.on('error', (e) => { console.error(e); });
req.write(data);
req.end();
import React, { useEffect, useState } from 'react';
function App() {
const [discountData, setDiscountData] = useState('');
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('https://easycms.fi/public_api/get_products_qty_discount', {
method: 'POST',
headers: {'Authorization1': 'TOKEN', 'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
username: 'USERNAME',
password: 'PASSWORD',
account: 'ACCOUNT_ID',
pid: 12345
}).toString()
});
const data = await response.text();
setDiscountData(data);
} catch (error) {
console.error(error);
}
};
fetchData();
}, []);
return ({discountData});
}
export default App;
import okhttp3.OkHttpClient
import okhttp3.FormBody
import okhttp3.Request
fun main() {
val client = OkHttpClient()
val formBody = FormBody.Builder()
.add("username", "USERNAME")
.add("password", "PASSWORD")
.add("account", "ACCOUNT_ID")
.add("pid", "12345")
.build()
val request = Request.Builder()
.url("https://easycms.fi/public_api/get_products_qty_discount")
.post(formBody)
.addHeader("Authorization1", "TOKEN")
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
println(response.body?.string())
}
}
using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var token = "TOKEN";
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair("username", "USERNAME"),
new KeyValuePair("password", "PASSWORD"),
new KeyValuePair("account", "ACCOUNT_ID"),
new KeyValuePair("pid", "12345")
});
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("Authorization1", token);
var response = await httpClient.PostAsync("https://easycms.fi/public_api/get_products_qty_discount", content);
if (response.IsSuccessStatusCode)
{
var responseData = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseData);
}
else
{
Console.WriteLine($"Error: {response.StatusCode}");
}
}
}
}
When you make a request to the endpoint, you receive a JSON response containing various keys and values. Here's an explanation of the response keys and their meanings:
- `start`: This represents the starting index for the data. In this case, it's set to 0, indicating that the data starts from the first item.
- `limit`: The maximum number of items returned in the response. In this example, the limit is set to 50, meaning that the response will include up to 50 items.
- `count`: The number of items included in the current response. In this case, there are 4 items in the response.
- `total_count`: The total count of items available in the dataset. In this response, there is a total of 4 items available.
- `pid`: The product ID that was queried.
- `id`: The unique identifier (UUID) for the discount tier record.
- `pid`: The product ID this discount tier belongs to.
- `crp_id`: The product reference ID from the products table.
- `min_qty`: The minimum quantity required to qualify for this discount.
- `discount`: The discount amount (interpretation depends on discount_type).
- `discount_type`: The type of discount. Only three values are ever returned by this endpoint: `0` = percentage, `1` = gross total line, `3` = gross per product. (Value `2` = "none" is an admin-UI sentinel for empty rows and is never stored in the database, so it never appears here.)
- `discount_type_label`: Human-readable label for the discount type ("percentage", "gross_total_line", "none", or "gross_per_product").
- `datenew`: The date and time when this discount tier was created (YYYY-MM-DD HH:MM:SS format).
These key-value pairs provide comprehensive information about the quantity discount tiers for a product and can be used for implementing tiered pricing in your application.
{
"INFO": {
"start": 0,
"limit": 50,
"count": 4,
"total_count": 4,
"pid": 12345
},
"OUTPUT": [
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"pid": 12345,
"crp_id": "PROD-001",
"min_qty": 10,
"discount": 5.00,
"discount_type": 0,
"discount_type_label": "percentage",
"datenew": "2024-01-15 10:30:00"
},
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"pid": 12345,
"crp_id": "PROD-001",
"min_qty": 25,
"discount": 10.00,
"discount_type": 0,
"discount_type_label": "percentage",
"datenew": "2024-01-15 10:30:00"
},
{
"id": "550e8400-e29b-41d4-a716-446655440003",
"pid": 12345,
"crp_id": "PROD-001",
"min_qty": 50,
"discount": 85.00,
"discount_type": 1,
"discount_type_label": "gross_total_line",
"datenew": "2024-01-15 10:30:00"
},
{
"id": "550e8400-e29b-41d4-a716-446655440004",
"pid": 12345,
"crp_id": "PROD-001",
"min_qty": 100,
"discount": 12.50,
"discount_type": 3,
"discount_type_label": "gross_per_product",
"datenew": "2024-01-15 10:30:00"
}
]
}
| Value | Label | Description |
|---|---|---|
| 0 | percentage | Discount is a percentage off the original price (e.g., 5 = 5% off) |
| 1 | gross_total_line | Discount represents the total gross price for ALL min_qty units (e.g., 85.00 = €85.00 total for 50 units) |
| 2 | none | No discount type selected (placeholder, not stored in DB) |
| 3 | gross_per_product | Discount represents the gross price per single unit (e.g., 12.50 = €12.50 per unit) |
Here are the possible error messages and their meanings:
| Error Code | HTTP Status | Description |
|---|---|---|
pid_parameter_is_required |
400 | The pid parameter is required |
pid_must_be_a_valid_positive_integer |
400 | The pid must be a valid integer |
product_not_found |
404 | The product with the specified pid does not exist |
UN-AUTHORIZED |
401 | Incorrect username or password |
this_account_does_not_exist_or_your_credentials_do_not_match_this_account |
401 | The account doesn't exist or mismatched credentials |
Maximum query size is 50 rows per query |
400 | Exceeded maximum limit of 50 rows per query |
{
"OUTPUT": {
"response_type": "error",
"message": "pid_parameter_is_required"
}
}
When a product exists but has no quantity discounts configured:
{
"INFO": {
"start": 0,
"limit": 50,
"count": 0,
"total_count": 0,
"pid": 12345
},
"OUTPUT": []
}
Use the quantity discount tiers to calculate the final price for a given quantity:
// Example in JavaScript
function calculateFinalPrice(basePrice, quantity, discountTiers) {
// Sort tiers by min_qty descending to find the applicable discount
const sortedTiers = discountTiers.sort((a, b) => b.min_qty - a.min_qty);
for (const tier of sortedTiers) {
if (quantity >= tier.min_qty) {
if (tier.discount_type === 0) {
// Percentage discount
return basePrice * (1 - tier.discount / 100);
} else if (tier.discount_type === 1) {
// Gross total line — discount is the total price for ALL min_qty units
const pricePerUnit = tier.discount / tier.min_qty;
return pricePerUnit * quantity;
} else if (tier.discount_type === 3) {
// Gross per product — discount is the price per single unit
return tier.discount * quantity;
}
}
}
// No discount applies
return basePrice * quantity;
}
// Usage
const basePrice = 100.00;
const quantity = 30;
const discountTiers = response.OUTPUT;
const finalPrice = calculateFinalPrice(basePrice, quantity, discountTiers);
console.log(`Final price for ${quantity} units: €${finalPrice.toFixed(2)}`);
Show customers the available discounts for larger quantities:
<table>
<thead>
<tr>
<th>Quantity</th>
<th>Discount</th>
</tr>
</thead>
<tbody>
<!-- Loop through OUTPUT array -->
<tr>
<td>10+</td>
<td>5% off</td>
</tr>
<tr>
<td>25+</td>
<td>10% off</td>
</tr>
<tr>
<td>50+</td>
<td>€85.00 total (gross total line)</td>
</tr>
<tr>
<td>100+</td>
<td>€12.50 each (gross per product)</td>
</tr>
</tbody>
</table>