Inventory & Products | Products | Multi-Location | Get Products Multi

Getting Product Multi-Location Data

This document outlines the procedure for making API calls to retrieve product multi-location data from https://easycms.fi/public_api/get_products_multi/. This includes location-specific pricing, barcodes, supplier info, and time-based scheduled pricing data.

Multi-Product Data Retrieval

Fetch multi-location product data effectively using the below API call. Apply different parameters to filter results according to your specific needs.

Scheduled Pricing Data

Each record in the response may include scheduled pricing fields. A record with scheduling fields is only active when the current time/date/day matches the defined schedule:

  • stime / etime: Time window (e.g., "11:00:00" to "14:00:00")
  • sdate / edate: Date range (e.g., "2025-06-01" to "2025-08-31")
  • days_list: Comma-separated day names (e.g., "monday,tuesday,wednesday,thursday,friday")
  • row_num: Priority order — lower numbers are evaluated first. The first matching schedule wins.

If all scheduling fields are NULL, the row is always active (permanent override).

Discount Ladder Flags (platform version 3.89+)

Each record also carries three per-row flags that steer how the row's discount competes with the product's own discount, quantity discount tiers and Buy-X-Get-X campaigns:

  • discount_lock: 1/0 — while this row wins the price resolution, its discount replaces the product's own discount and quantity discount tiers are skipped. Customer-specific prices and VIP discounts still apply (the bigger discount wins). The lock has no effect when the row carries no discount.
  • ignore_qty_discount: 1/0 — quantity discount tiers are skipped on lines priced from this row.
  • ignore_bxgx: 1/0 — Buy-X-Get-X free units are not generated on lines priced from this row.

Rows within the same product resolve by row_num (later rows win the fields they set); a row carrying a location and/or its own barcode/boxcode is specific — its discount replaces the product's general discount even when smaller. The flags are returned on accounts running platform version 3.89 or newer; older accounts simply omit them. They can be managed via Set Products Multi.

Endpoint and Method

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

Parameters | Payload

Each parameter can be used individually or in combination to refine your data retrieval:

  • 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.
  • Pagination: To manage data effectively, this endpoint supports fetching up to 50 multi-product records at a time.
  • Parameters:
    • start - Specify the starting point of the row from which to begin fetching records.
    • limit - Control the number of records returned in a single request. The maximum limit is 50, but you can opt for a smaller number based on your needs.



Filters

To manage data effectively, this endpoint supports fetching up to 50 multi-product records at a time. Each filter parameter is optional and designed to refine your search.

  • pid: To filter by a single product ID. The value needs to be an integer.
  • supplier_id: To filter by supplier ID. The value needs to be an integer.
  • location_id: To filter by location ID. The value needs to be a string.



Call Examples in Different Languages


# Get all multi-location records
curl -X POST 'https://easycms.fi/public_api/get_products_multi' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID'

# Get multi-location records for a specific product
curl -X POST 'https://easycms.fi/public_api/get_products_multi' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&pid=12345'

# Get multi-location records for a specific location
curl -X POST 'https://easycms.fi/public_api/get_products_multi' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&location_id=loc_001'

$curl = curl_init();
curl_setopt_array($curl, array(
  CURLOPT_URL => "https://easycms.fi/public_api/get_products_multi",
  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_multi"
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_multi"))
    .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_multi',
  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 [productMultiData, setProductMultiData] = useState('');
  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch('https://easycms.fi/public_api/get_products_multi', {
          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();
        setProductMultiData(data);
      } catch (error) {
        console.error(error);
      }
    };
    fetchData();
  }, []);
  return (<div>{productMultiData}</div>);
}
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_multi")
        .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<string, string>("username", "USERNAME"),
            new KeyValuePair<string, string>("password", "PASSWORD"),
            new KeyValuePair<string, string>("account", "ACCOUNT_ID"),
            new KeyValuePair<string, string>("pid", "12345")
        });
        using (var httpClient = new HttpClient())
        {
            httpClient.DefaultRequestHeaders.Add("Authorization1", token);
            var response = await httpClient.PostAsync("https://easycms.fi/public_api/get_products_multi", 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`: Starting index for the data. Set to 0 for the first page.
- `limit`: Maximum number of records returned (up to 50).
- `count`: Number of records in this response.
- `total_count`: Total records matching the filters.
- `WHERE`: (Optional) Filter conditions applied to the query.
    

- `multi_id`: Unique record UUID (string) - Can be used with set_products_multi to target specific records for update or deletion.
- `pid`: Product ID (integer) - The product this record belongs to.
- `crp_id`: Currency profile ID (string) - Links to currency settings.
- `code`: Barcode/SKU (string) - Location-specific barcode for this product.
- `boxcode`: Box code (string) - Box code for this location.
- `supplier_id`: Supplier ID (integer) - Supplier for this location.
- `crsupplier_id`: Cash Register Supplier ID (string).
- `pricebuy`: Buy price (decimal) - Purchase price at this location.
- `price`: Sell price (decimal) - Net selling price at this location.
- `discount`: Discount percentage (decimal).
- `location_id`: Location ID (string) - The location this record applies to.
- `row_num`: Priority order (integer) - Lower = higher priority. First matching row wins for scheduled pricing.

**Scheduled Pricing Fields:**
- `stime`: Start time (time) - Start of time window (e.g., "11:00:00"). NULL = no time restriction.
- `etime`: End time (time) - End of time window (e.g., "14:00:00"). NULL = no time restriction.
- `sdate`: Start date (date) - Start of date range (e.g., "2025-06-01"). NULL = no start date.
- `edate`: End date (date) - End of date range (e.g., "2025-08-31"). NULL = no end date.
- `days_list`: Day names (string) - Comma-separated day names (e.g., "monday,tuesday,wednesday,thursday,friday"). NULL = no day restriction.

**Discount Ladder Flags (platform version 3.89+):**
- `discount_lock`: Lock discount (integer, 1/0) - While this row wins the price resolution, its discount replaces the product's own discount and quantity tiers are skipped (customer pricing/VIP still compete). Inert when the row has no discount.
- `ignore_qty_discount`: Ignore quantity discounts (integer, 1/0) - Quantity discount tiers are skipped on lines priced from this row.
- `ignore_bxgx`: Ignore Buy-X-Get-X (integer, 1/0) - BXGX free units are suppressed on lines priced from this row.
    

{
  "INFO": {
    "start": 0,
    "limit": 50,
    "count": 2,
    "total_count": 2,
    "WHERE": "pid = 12345"
  },
  "OUTPUT": [
    {
      "multi_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "pid": "12345",
      "crp_id": "abc123",
      "code": "LOC-SPECIFIC-BARCODE",
      "boxcode": "BOX-001",
      "supplier_id": "10",
      "crsupplier_id": null,
      "pricebuy": 15.5,
      "row_num": 0,
      "price": 19.99,
      "discount": 0,
      "discount_lock": 0,
      "ignore_qty_discount": 0,
      "ignore_bxgx": 0,
      "location_id": "loc_001",
      "stime": null,
      "etime": null,
      "sdate": null,
      "edate": null,
      "days_list": null
    },
    {
      "multi_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "pid": "12345",
      "crp_id": "abc123",
      "code": null,
      "boxcode": null,
      "supplier_id": "0",
      "crsupplier_id": null,
      "pricebuy": null,
      "row_num": 1,
      "price": 12.99,
      "discount": 15,
      "discount_lock": 1,
      "ignore_qty_discount": 1,
      "ignore_bxgx": 0,
      "location_id": "loc_001",
      "stime": "11:00:00",
      "etime": "14:00:00",
      "sdate": "2025-06-01",
      "edate": "2025-08-31",
      "days_list": "monday,tuesday,wednesday,thursday,friday"
    }
  ],
  "success": true,
  "message": "Data returned successfully"
}
      

Error Handling

Here are the possible error messages and their meanings:

  • UN-AUTHORIZED - _user_name_password_is_set_but_wrong_value!: Incorrect username or password.
  • this_account_does_not_exist_or_your_credentials_do_not_match_this_account: The account doesn't exist or mismatched credentials.
  • UN-AUTHORIZED - header is set but the header value is not correct!: Incorrect authorization header value.
  • maximum_query_size_is_50_rows_per_query: Exceeded maximum limit of 50 rows per query.
  • pid_must_be_a_valid_positive_integer: Invalid pid parameter value.
  • supplier_id_must_be_a_valid_positive_integer: Invalid supplier_id parameter value.
  • error_retrieving_product_multi_data: A database error occurred while retrieving data.
  • NOT AUTHORIZED!: Authentication failed - no valid credentials provided.

Related Endpoints