Conventions
Base URL, content types, currencies, pagination, timestamps, country codes, demo data markers, and other conventions that apply across every Haszno API endpoint.
Base URL
All endpoints are served from one base URL:
https://haszno.com
There is no version prefix in any path. The API is an unversioned developer preview; see Changelog for the versioning policy.
Content types
| Direction | Header | Value |
|---|---|---|
| Request body | Content-Type |
application/json |
| JSON responses | Content-Type |
application/json |
/api/blog/rss.xml |
Content-Type |
application/rss+xml; charset=utf-8 |
/api/blog/feed.json |
Content-Type |
application/feed+json; charset=utf-8 |
/api/blog/:slug.md |
Content-Type |
text/markdown; charset=utf-8 |
/llms.txt |
Content-Type |
text/plain |
Send Content-Type: application/json on every request that includes a body. A body that is not valid JSON or fails validation returns 400. The account endpoints (POST /api/auth/register, POST /api/auth/login, POST /api/auth/tokens) also return 400 when the header is missing.
Currency and prices
All monetary values are integers in Hungarian Forints (HUF, ISO 4217). There are no decimal prices.
| Suffix | Meaning | Example field |
|---|---|---|
Net |
Excludes VAT | costNet, marginNet |
Gross |
Includes VAT | priceGross, rrpGross, floorGross |
The default VAT rate is 27 % (vatPct: 27), matching the Hungarian standard rate. The vatPct parameter on demo endpoints lets you change this for a single request; it does not persist.
Margin and floor formulas, with net = priceGross / (1 + vatPct / 100):
marginNet = round(net − costNet): the net selling price minus the net cost, in whole forints.marginPct = (net − costNet) / net × 100, rounded to one decimal place;0whennetis not positive.marginNetandmarginPctare bothnullwhencostNetisnull.floorGross = costNet / (1 − minMarginPct / 100) × (1 + vatPct / 100), rounded up to the next price ending in 90 Ft (for example 72 431 → 72 490).
marginPct is a percentage with at most one decimal place, for example 31.9. Every other price, cost and margin field is an integer.
Null semantics
A null price or cost field means the value is unknown or unavailable, not zero. Treat null and 0 differently:
| Field | null means |
|---|---|
costNet: null |
Purchase cost unknown; marginNet and marginPct are null and recommended.status is nincs_besz_ar. |
marketMinGross: null |
No market price found in the requested shipping markets. |
rrpGross: null |
Supplier has not set a recommended retail price. |
Do not substitute zero for null in price comparisons or margin calculations.
Timestamps
All timestamps are ISO 8601 strings in UTC, e.g. 2026-11-10T00:00:00.000Z.
The API does not use Unix epoch integers. Demo timestamps such as fetchedAt and addedAt are fixed synthetic values and do not reflect real events; the from and to window of GET /api/impact is computed from the current time.
Country codes and market parameters
Country codes follow ISO 3166-1 alpha-2 (two uppercase letters, e.g. HU, SK).
The shippingMarkets query parameter accepts one or more country codes separated by commas. Valid values:
| Code | Country |
|---|---|
HU |
Hungary |
SK |
Slovakia |
DE |
Germany |
AT |
Austria |
CZ |
Czech Republic |
PL |
Poland |
RO |
Romania |
Default when omitted: HU.
In responses, marketByCountry has three fixed keys: hu (Hungary), sk (Slovakia), and eu (all other supported markets — DE, AT, CZ, PL, RO). A slot is null when no market price is available for that market.
Pagination
Pagination applies to four endpoints only:
| Endpoint | Style |
|---|---|
GET /api/catalogue/products |
Page-based: ?page= (1-based, default 1) + ?pageSize= (1–100, default 24). Returns { items, total, facets }. |
GET /api/rule-runs |
Limit: ?limit=N (default 30, max 200). |
GET /api/proposals |
Limit: ?limit=N (default 50, max 200). |
GET /api/blog |
Page-based: ?page= (1-based, default 1), fixed page size of 10. Returns { posts, total, page, perPage }. |
All other list endpoints return all matching rows in a single response. There is no cursor, Link header, or nextPage field on these endpoints. Pagination parameters sent to them are silently ignored.
GET /api/orders returns the last 50 orders only, with no mechanism to page further.
Demo and synthetic data
The public demo at https://haszno.com serves synthetic sample data on its unauthenticated GET endpoints. Only the object responses of GET /api/settings and GET /api/impact carry a top-level field:
"demo": true
Array responses have no such field. Recognise them by these markers:
| Marker | Where | Meaning |
|---|---|---|
"sku": "DEMO-{id}" |
Products | Placeholder SKU, not a real supplier code. |
"source": "mock" |
Market price records | Not a verified competitor price. |
"partnerCount": 0 |
Categories | Real connected-partner count; always 0 on the demo. |
GET /api/orders and GET /api/proposals return [] on the public demo. This is by design; the demo does not simulate order history. Do not interpret an empty array as evidence that the endpoint works with real data.
Language of API messages
API error messages and status enum strings are currently in Hungarian only, regardless of the Accept-Language header or the documentation language you are reading.
Examples:
| String | Context |
|---|---|
"error": "Ismeretlen cikkszám: DEMO-99" |
400 error from POST /api/webhooks/order |
recommended.status: "versenykepes" |
The recommended price undercuts the cheapest market price and stays at or above the floor |
recommended.status: "nem_versenykepes" |
Undercutting the market would break the minimum margin; the recommended price is the floor |
recommended.status: "nincs_piaci_ar" |
No market price known; the recommended price is the RRP or the floor |
recommended.status: "nincs_besz_ar" |
Purchase cost unknown; no pricing recommendation can be made |
This will change before general availability. The recommended.status values are described in GET /api/products; HTTP status codes are listed in Errors.
CORS
The API enforces strict same-origin CORS. The allowed origin is set server-side from the CORS_ORIGIN environment variable, falling back to PUBLIC_URL, then http://localhost:5180. On haszno.com the allowed origin is the production front-end.
| CORS setting | Value |
|---|---|
| Allowed methods | GET POST PUT PATCH DELETE OPTIONS |
| Allowed request headers | Content-Type, Authorization, x-api-key, x-support-token |
| Credentials (cookies) | Forwarded (credentials: true) |
| Preflight cache | 600 seconds |
Requests from an unlisted origin are rejected. Use https://haszno.com as the base URL.
Request body size limit
| Endpoint | Limit |
|---|---|
POST /api/feeds/import |
10 MB |
| All other endpoints | 1 MB |
Requests exceeding the limit return 413 Content Too Large. See Errors.
.com