Locations
Warehouses and other stock locations. These belong to the company, not to a single store.
Paste a key and every snippet on this page switches from the placeholder to your key — and the Try it panel under each endpoint is ready to send. It is stored in this browser only and goes nowhere except, if you press Send, straight to the API host you pick there.
List locations
/ext/v1/locationslocations:readLocations belong to the COMPANY and are shared across its stores, so they carry company_id rather than store_id and store_id= does not narrow them.
Query parameters
| Name | Type | Description |
|---|---|---|
limit | numberdefault 25max 100 | Page size. |
starting_after | string | Return the page AFTER this object id (the previous page's next_cursor). |
ending_before | string | Return the page BEFORE this object id. |
sort | stringdefault -created_at | Newest first by default. Only created_at is sortable — a cursor over a mutable key (like updated_at) cannot page reliably. Use updated_after to sync changes.created_at-created_at |
store_id | string | Restrict to one store. Required breadth control for company-scoped keys; on a store-scoped key it must match the key's own store. |
Request
export SALAF_API_KEY="salaf_sk_YOUR_API_KEY"
curl -sS "https://api.salafems.com/ext/v1/locations?limit=25" \
-H "Authorization: Bearer $SALAF_API_KEY"const url = new URL("https://api.salafems.com/ext/v1/locations");
Object.entries({
limit: "25",
}).forEach(([key, value]) => url.searchParams.set(key, value));
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${process.env.SALAF_API_KEY}`,
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.code}: ${error.message} [${error.request_id}]`);
}
const { data, meta } = await response.json();import os
import requests
response = requests.get(
"https://api.salafems.com/ext/v1/locations",
params={
"limit": "25",
},
headers={
"Authorization": f"Bearer {os.environ['SALAF_API_KEY']}",
},
timeout=30,
)
if not response.ok:
error = response.json()["error"]
raise RuntimeError(f"{error['code']}: {error['message']}")
page = response.json()
rows, meta = page["data"], page["meta"]<?php
$key = getenv('SALAF_API_KEY');
$ch = curl_init('https://api.salafems.com/ext/v1/locations?limit=25');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key],
CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$response = json_decode($body, true);
if ($status >= 400) {
throw new RuntimeException("{$response['error']['code']}: {$response['error']['message']}");
}
$rows = $response['data'];
$meta = $response['meta'];https://api.salafems.com/ext/v1/locationsStored in this browser only and never sent anywhere except to the API host you picked above — these pages are static files with no server behind them.
Query parameters
Blank fields are left out of the request.
Paste a key above to enable Send.
Responses
200A cursor page of locations.401Missing/invalid API key, revoked or expired key, plan without API access, or a dead store.403The key's scopes do not cover this endpoint.422Validation failed —error.fieldsmaps each offending field to its messages.429Rate limit exceeded for this key. HonorRetry-Afterand theX-RateLimit-*headers.
Every failure uses the one error envelope — Errors lists each code and what to do with it.
{
"data": [
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"company_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Main Warehouse",
"code": "WH-01",
"address": null,
"status": "active",
"is_default": true,
"latitude": "23.8103",
"longitude": "90.4125",
"created_at": "2026-08-11T10:00:00.000Z",
"updated_at": "2026-08-11T10:00:00.000Z"
}
],
"meta": {
"has_more": true,
"next_cursor": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001"
}
}Get a location by id
/ext/v1/locations/{id}locations:readOne location (warehouse) record.
Path parameters
| Name | Type | Description |
|---|---|---|
idrequired | uuid | The location id. |
Query parameters
| Name | Type | Description |
|---|---|---|
store_id | uuid | Restrict the lookup to one store. Breadth control for company-scoped keys; on a store-scoped key it must match the key's own store. |
Request
export SALAF_API_KEY="salaf_sk_YOUR_API_KEY"
curl -sS "https://api.salafems.com/ext/v1/locations/REPLACE_WITH_ID" \
-H "Authorization: Bearer $SALAF_API_KEY"const url = new URL("https://api.salafems.com/ext/v1/locations/REPLACE_WITH_ID");
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${process.env.SALAF_API_KEY}`,
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.code}: ${error.message} [${error.request_id}]`);
}
const object = await response.json();import os
import requests
response = requests.get(
"https://api.salafems.com/ext/v1/locations/REPLACE_WITH_ID",
headers={
"Authorization": f"Bearer {os.environ['SALAF_API_KEY']}",
},
timeout=30,
)
if not response.ok:
error = response.json()["error"]
raise RuntimeError(f"{error['code']}: {error['message']}")
obj = response.json()<?php
$key = getenv('SALAF_API_KEY');
$ch = curl_init('https://api.salafems.com/ext/v1/locations/REPLACE_WITH_ID');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key],
CURLOPT_TIMEOUT => 30,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$response = json_decode($body, true);
if ($status >= 400) {
throw new RuntimeException("{$response['error']['code']}: {$response['error']['message']}");
}https://api.salafems.com/ext/v1/locations/5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001Stored in this browser only and never sent anywhere except to the API host you picked above — these pages are static files with no server behind them.
Path parameters
Query parameters
Blank fields are left out of the request.
Paste a key above to enable Send.
Responses
200The location.401Missing/invalid API key, revoked or expired key, plan without API access, or a dead store.403The key's scopes do not cover this endpoint.404Location not found.422Validation failed —error.fieldsmaps each offending field to its messages.429Rate limit exceeded for this key. HonorRetry-Afterand theX-RateLimit-*headers.
Every failure uses the one error envelope — Errors lists each code and what to do with it.
{
"id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"company_id": "5f7d2f60-0d1c-4b3a-9a68-6f4d21f6a001",
"name": "Main Warehouse",
"code": "WH-01",
"address": null,
"status": "active",
"is_default": true,
"latitude": "23.8103",
"longitude": "90.4125",
"created_at": "2026-08-11T10:00:00.000Z",
"updated_at": "2026-08-11T10:00:00.000Z"
}