API reference

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; 0 when net is not positive.
  • marginNet and marginPct are both null when costNet is null.
  • 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.