Conventions¶
The same rules apply to every endpoint — learn them once.
Response envelope¶
Success:
{
"success": true,
"data": { /* object */ } ,
"meta": { /* optional: pagination, balances, receipts */ }
}
data is either a single object or an array, depending on the endpoint. meta is present on
list endpoints (pagination) and on writes that produce side data (a new account balance, a
fiscal receipt, …).
Error:
{
"success": false,
"error": { "code": "validation_error", "message": "name is required",
"details": { "field": "name" } }
}
code is a stable string (see Errors); message is human-readable; details is
optional structured context. The HTTP status matches the error (4xx/5xx).
Data types¶
| Type | Rule | Example |
|---|---|---|
| Money | exact decimal string, never a float | "1234.50" |
| Time | ISO-8601, UTC | "2026-07-20T08:28:59" |
| Quantity | number (int when whole) | 3, 1.5 |
| Boolean | real true/false (not 0/1) |
true |
| Missing value | null (the internal 0/"" sentinels are normalised) |
null |
| Keys | snake_case |
warehouse_id |
Money is a string so you never lose precision to floating point. Parse it with a decimal type.
Pagination¶
List endpoints accept ?limit= and ?offset=:
curl "https://crm.h-profit.com/bapi-v2/products?limit=50&offset=100" \
-H "Authorization: hp_live_your_key_here"
limitis clamped to each resource's maximum (defaults vary; e.g. products 100, sales up to 5000).- The
metablock echoes the paging:
Page by increasing offset until you receive fewer than limit rows.
Fetching a whole list at once¶
Reference-style resources — suppliers, categories, product_sync — are paginated by
default too, but you can pull the entire list in one request with ?all=1:
curl "https://crm.h-profit.com/bapi-v2/categories?all=1" \
-H "Authorization: hp_live_your_key_here"
meta.limit comes back as null to signal that no cap was applied:
Reach for ?all=1 when you need the full set locally (a category tree, a product→remote binding
map); for large tables prefer normal paging. (categories?tree=1 also returns the whole set,
already nested.)
HTTP methods¶
| Method | Meaning |
|---|---|
GET |
read (list or single) |
POST |
create (or a bulk action) |
PUT |
update |
DELETE |
delete |
Request bodies are JSON (Content-Type: application/json). Filters for GET go in the query
string; bodies for POST/PUT/DELETE go in JSON.
Rate limits¶
Each API key may make 120 requests per minute. The minute starts with the key's first request,
and every request counts, including ones that fail. A composite /query counts as one
request. Every response carries the current state:
| Header | Meaning |
|---|---|
X-RateLimit-Limit |
requests allowed per minute |
X-RateLimit-Remaining |
requests left in the current minute |
X-RateLimit-Reset |
seconds until the counter resets |
Over the limit the API answers 429 with code: rate_limited and a Retry-After header
(seconds to wait). If your integration needs a higher limit, contact support.
CORS¶
All responses send permissive CORS headers (Access-Control-Allow-Origin: *) and answer
OPTIONS preflight with 204, so the API can be called from a browser.
Localisation¶
Some values (category names, units) are localised to the key owner's account language, not the request. There is no per-request language switch.