Inventory & Products | Products | Qty Discounts | Get Qty Discounts

Getting Product Quantity Discounts

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/.

Important Note

The pid (Product ID) parameter is MANDATORY for this endpoint. You must provide a valid product ID to retrieve quantity discount tiers.

Product Quantity Discount Data Retrieval

Fetch quantity discount tiers for a specific product. Quantity discounts allow you to offer tiered pricing based on the quantity purchased.

Endpoint and Method

  • Endpoint: https://easycms.fi/public_api/get_products_qty_discount/
  • Method: GET or POST

Parameters | Payload

  • 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.

Required Parameter

  • pid: Product ID (MANDATORY) - The ID of the product to retrieve quantity discounts for. Must be an integer.

Pagination Parameters

  • 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).



Call Examples in Different Languages


# 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}");
            }
        }
    }
}




Handling Endpoint Results

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"
    }
  ]
}
      

Discount Types

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)

Error Handling

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

Error Response Example

{
  "OUTPUT": {
    "response_type": "error",
    "message": "pid_parameter_is_required"
  }
}

Empty Response

When a product exists but has no quantity discounts configured:

{
  "INFO": {
    "start": 0,
    "limit": 50,
    "count": 0,
    "total_count": 0,
    "pid": 12345
  },
  "OUTPUT": []
}

Use Cases

Calculate Final Price Based on Quantity

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)}`);

Display Quantity Discount Table

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>

Related Endpoints

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/.

Important Note

The pid (Product ID) parameter is MANDATORY for this endpoint. You must provide a valid product ID to retrieve quantity discount tiers.

Product Quantity Discount Data Retrieval

Fetch quantity discount tiers for a specific product. Quantity discounts allow you to offer tiered pricing based on the quantity purchased.

Endpoint and Method

  • Endpoint: https://easycms.fi/public_api/get_products_qty_discount/
  • Method: GET or POST

Parameters | Payload

  • 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.

Required Parameter

  • pid: Product ID (MANDATORY) - The ID of the product to retrieve quantity discounts for. Must be an integer.

Pagination Parameters

  • 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).



Call Examples in Different Languages


# 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}");
            }
        }
    }
}




Handling Endpoint Results

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"
    }
  ]
}
      

Discount Types

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)

Error Handling

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

Error Response Example

{
  "OUTPUT": {
    "response_type": "error",
    "message": "pid_parameter_is_required"
  }
}

Empty Response

When a product exists but has no quantity discounts configured:

{
  "INFO": {
    "start": 0,
    "limit": 50,
    "count": 0,
    "total_count": 0,
    "pid": 12345
  },
  "OUTPUT": []
}

Use Cases

Calculate Final Price Based on Quantity

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)}`);

Display Quantity Discount Table

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>

Related Endpoints