This document outlines the procedure for making API calls to retrieve product stock data from https://easycms.fi/public_api/get_products_stock/.
The pid (Product ID) parameter is MANDATORY for this endpoint. You must provide at least one valid product ID to retrieve stock data.
All filter parameters (pid, location_id, shelf_id) accept three input formats for flexibility:
| Format | Example | Description |
|---|---|---|
| Single value | pid=5 |
Returns data for one product |
| Array | pid[]=5&pid[]=10&pid[]=15 |
Returns data for multiple products |
| JSON array | pid=[5,10,15] |
Same as array, sent as JSON string |
This allows you to query stock for multiple products, locations, or shelves in a single API call — reducing round trips and simplifying integration code.
When multiple filters use arrays, they are combined with AND logic. For example:
pid=[1,2]&location_id=[5,8] → stock for products 1 and 2 at locations 5 and 8pid=123&location_id=5&shelf_id=[1,3,7] → stock for product 123 at location 5 on shelves 1, 3, and 7Fetch product stock data for all locations/shelves or filter by specific locations and shelves.
https://easycms.fi/public_api/get_products_stock/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(s) of the product(s) to retrieve stock for. Accepts single integer, array, or JSON array (see Multi-Value Parameters above).location_id: Filter results by location ID(s). Accepts single integer, array, or JSON array. When provided, returns stock only for the specified location(s).shelf_id: Filter results by shelf ID(s). Accepts single integer, array, or JSON array. Note: Requires location_id to be provided as well.start - Specify the starting point of the row from which to begin fetching stock data (default: 0).limit - Control the number of stock records returned in a single request (default: 50, max: 50).
# Get all stock for a single product
curl -X POST 'https://easycms.fi/public_api/get_products_stock' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&pid=12345'
# Get stock for a specific location
curl -X POST 'https://easycms.fi/public_api/get_products_stock' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&pid=12345&location_id=1'
# Get stock for a specific location and shelf
curl -X POST 'https://easycms.fi/public_api/get_products_stock' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&pid=12345&location_id=1&shelf_id=5'
# Get stock for MULTIPLE products (array format)
curl -X POST 'https://easycms.fi/public_api/get_products_stock' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&pid[]=12345&pid[]=67890&pid[]=11111'
# Get stock for MULTIPLE products (JSON format)
curl -X POST 'https://easycms.fi/public_api/get_products_stock' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&pid=[12345,67890,11111]'
# Get stock for MULTIPLE locations (all shelves in each)
curl -X POST 'https://easycms.fi/public_api/get_products_stock' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&pid=12345&location_id=[1,2,5]'
# Get stock for multiple products at multiple locations
curl -X POST 'https://easycms.fi/public_api/get_products_stock' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&pid=[12345,67890]&location_id=[1,2]'
# Get stock for specific shelves across locations
curl -X POST 'https://easycms.fi/public_api/get_products_stock' \
-H 'Authorization1: TOKEN' \
-d 'username=USERNAME&password=PASSWORD&account=ACCOUNT_ID&pid=12345&location_id=[1,2]&shelf_id=[3,5]'
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://easycms.fi/public_api/get_products_stock",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query([
'username' => 'USERNAME',
'password' => 'PASSWORD',
'account' => 'ACCOUNT_ID',
'pid' => [12345, 67890], // multiple products
'location_id' => [1, 2], // multiple locations (optional)
'shelf_id' => [3, 5] // multiple shelves (optional)
]),
CURLOPT_HTTPHEADER => array("Authorization1: TOKEN"),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
import requests
url = "https://easycms.fi/public_api/get_products_stock"
headers = {"Authorization1": "TOKEN"}
payload = {
'username': 'USERNAME',
'password': 'PASSWORD',
'account': 'ACCOUNT_ID',
'pid[]': [12345, 67890], # multiple products (array format)
'location_id[]': [1, 2], # multiple locations (optional)
'shelf_id[]': [3, 5] # multiple shelves (optional)
}
response = requests.post(url, headers=headers, data=payload)
print(response.text)
HttpClient client = HttpClient.newHttpClient();
// Multiple products and locations using array format
String formData = "username=USERNAME&password=PASSWORD&account=ACCOUNT_ID"
+ "&pid[]=12345&pid[]=67890"
+ "&location_id[]=1&location_id[]=2";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://easycms.fi/public_api/get_products_stock"))
.headers("Authorization1", "TOKEN")
.POST(HttpRequest.BodyPublishers.ofString(formData))
.build();
HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
const https = require('https');
const params = new URLSearchParams({
username: 'USERNAME',
password: 'PASSWORD',
account: 'ACCOUNT_ID',
// Multiple products as JSON array
pid: JSON.stringify([12345, 67890]),
// Multiple locations as JSON array
location_id: JSON.stringify([1, 2])
});
const options = {
hostname: 'easycms.fi',
path: '/public_api/get_products_stock',
method: 'POST',
headers: {
'Authorization1': 'TOKEN',
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(params.toString())
}
};
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(params.toString());
req.end();
import React, { useEffect, useState } from 'react';
function App() {
const [stockData, setStockData] = useState('');
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('https://easycms.fi/public_api/get_products_stock', {
method: 'POST',
headers: {'Authorization1': 'TOKEN', 'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
username: 'USERNAME',
password: 'PASSWORD',
account: 'ACCOUNT_ID',
pid: JSON.stringify([12345, 67890]),
location_id: JSON.stringify([1, 2])
}).toString()
});
const data = await response.text();
setStockData(data);
} catch (error) {
console.error(error);
}
};
fetchData();
}, []);
return (<div>{stockData}</div>);
}
export default App;
import okhttp3.OkHttpClient
import okhttp3.FormBody
import okhttp3.Request
fun main() {
val client = OkHttpClient()
// Multiple products using array format
val formBody = FormBody.Builder()
.add("username", "USERNAME")
.add("password", "PASSWORD")
.add("account", "ACCOUNT_ID")
.add("pid[]", "12345")
.add("pid[]", "67890")
.add("location_id[]", "1")
.add("location_id[]", "2")
.build()
val request = Request.Builder()
.url("https://easycms.fi/public_api/get_products_stock")
.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";
// Multiple products and locations
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair("username", "USERNAME"),
new KeyValuePair("password", "PASSWORD"),
new KeyValuePair("account", "ACCOUNT_ID"),
new KeyValuePair("pid[]", "12345"),
new KeyValuePair("pid[]", "67890"),
new KeyValuePair("location_id[]", "1"),
new KeyValuePair("location_id[]", "2")
});
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("Authorization1", token);
var response = await httpClient.PostAsync("https://easycms.fi/public_api/get_products_stock", 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.
- `WHERE`: The filter conditions applied to the query. Shows which pids, location_ids, and shelf_ids were used.
- `pid`: The product ID for this stock entry.
- `location_id`: The unique identifier for the location/warehouse.
- `location_name`: The name of the location/warehouse.
- `shelf_id`: The unique identifier for the shelf within the location.
- `shelf_name`: The name of the shelf.
- `stock`: The current stock quantity at this location/shelf combination.
- `best_before_date`: The best before date for the stock at this location (YYYY-MM-DD format, null if not set).
- `default_location`: Flag indicating if this is the default location for the product (1 = yes, 0 = no).
- `location_shelf_combo_id`: A combined identifier in format "location_id-shelf_id" for easy reference.
These key-value pairs provide comprehensive information about the product stock across all locations and can be used for inventory management in your application.
{
"INFO": {
"start": 0,
"limit": 50,
"count": 4,
"total_count": 4,
"WHERE": "pid IN (12345, 67890) AND location_id IN (1, 2)"
},
"OUTPUT": [
{
"pid": 12345,
"location_id": 1,
"location_name": "Main Warehouse",
"shelf_id": 5,
"shelf_name": "Shelf A1",
"stock": 150.5,
"best_before_date": "2025-12-31",
"default_location": 1,
"location_shelf_combo_id": "1-5"
},
{
"pid": 12345,
"location_id": 2,
"location_name": "Secondary Warehouse",
"shelf_id": 3,
"shelf_name": "Shelf B2",
"stock": 50.0,
"best_before_date": "2025-06-30",
"default_location": 0,
"location_shelf_combo_id": "2-3"
},
{
"pid": 67890,
"location_id": 1,
"location_name": "Main Warehouse",
"shelf_id": 2,
"shelf_name": "Shelf A2",
"stock": 200.0,
"best_before_date": null,
"default_location": 1,
"location_shelf_combo_id": "1-2"
},
{
"pid": 67890,
"location_id": 2,
"location_name": "Secondary Warehouse",
"shelf_id": 1,
"shelf_name": "Shelf B1",
"stock": 75.0,
"best_before_date": "2026-03-15",
"default_location": 0,
"location_shelf_combo_id": "2-1"
}
]
}
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_or_array |
400 | The pid must be a valid integer or array of integers |
product_not_found_pid_{N} |
404 | The product with the specified pid does not exist |
location_id_must_be_a_valid_positive_integer_or_array |
400 | location_id must be valid integer(s) |
location_not_found_id_{N} |
404 | The specified location does not exist |
shelf_id_must_be_a_valid_positive_integer_or_array |
400 | shelf_id must be valid integer(s) |
location_id_is_required_when_shelf_id_is_provided |
400 | shelf_id cannot be used without location_id |
shelf_not_found_id_{N} |
404 | The specified shelf 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 |
{
"status": "error",
"error_code": "MISSING_PID",
"message": "The pid parameter is required"
}
When products exist but have no stock data:
{
"INFO": {
"start": 0,
"limit": 50,
"count": 0,
"total_count": 0,
"WHERE": "pid IN (12345, 67890)"
},
"OUTPUT": []
}
Query stock for several products across multiple warehouses in a single call:
POST /get_products_stock?pid=[12345,67890]&location_id=[1,2]
To calculate the total stock for a product across all locations, omit location_id and sum the stock values:
const response = await getProductsStock({pid: 12345});
const totalStock = response.OUTPUT.reduce((sum, item) => sum + item.stock, 0);
console.log(`Total stock: ${totalStock}`);
POST /get_products_stock?pid[]=12345&pid[]=67890&pid[]=11111
Use location_id as an array to check stock at multiple warehouses:
POST /get_products_stock?pid=12345&location_id[]=1&location_id[]=2&location_id[]=5
Use both location_id and shelf_id with arrays to check specific shelves:
POST /get_products_stock?pid=12345&location_id=[1,2]&shelf_id=[3,5]
Look for the item where default_location is 1 to find the primary stocking location for a product.
When querying many products/locations, results are limited to 50 rows. Use pagination:
POST /get_products_stock?pid=[1,2,3,4,5]&start=0&limit=50
POST /get_products_stock?pid=[1,2,3,4,5]&start=50&limit=50
| Parameter | Single | Array | JSON |
|---|---|---|---|
pid |
pid=5 |
pid[]=5&pid[]=10 |
pid=[5,10] |
location_id |
location_id=1 |
location_id[]=1&location_id[]=2 |
location_id=[1,2] |
shelf_id |
shelf_id=3 |
shelf_id[]=3&shelf_id[]=5 |
shelf_id=[3,5] |