Requests, paging, errors and rate limits
Headers, paging, search and sorting, every error code, rate-limit headers, request ids and size limits.
Request headers
| Header | When |
|---|---|
Authorization: Bearer lnk_… (or X-Api-Key) | Every request |
Content-Type: application/json | Requests with a body |
Accept: application/json | Recommended |
X-Request-Id | Optional: your own id (8–64 letters, digits, - or _) to trace a call; otherwise we make one |
Paging, search and sorting
Lists return 50 records by default. Use per_page (up to 200) and page:
curl "https://api.leisurenexus.app/v1/items?per_page=200&page=2" -H "Authorization: Bearer lnk_…"
{
"data": [ ... ],
"meta": { "page": 2, "pages": 14, "per_page": 200, "total": 2716, "from": 201, "to": 400 }
}
Keep asking for the next page until page equals pages. Pages are in a stable order, so nothing is skipped or repeated while you page.
| Parameter | Lists | Meaning |
|---|---|---|
search | items, stock, customers, orders | Part of a name, SKU, company or receipt number |
sort | items (name, updated, sku), customers (name, updated), orders (completed, total) | Sort field |
dir | same | asc or desc |
updated_since | items, customers | Only records changed after this time — ideal for syncing |
Errors
Every error has the same shape:
{
"error": {
"code": "missing_scope",
"message": "This key can't do that: it needs the customers.read scope."
}
}
Invalid input adds fields, with messages per field:
{
"error": {
"code": "invalid_request",
"message": "Another customer has this phone number.",
"fields": { "phone": ["Another customer has this phone number."] }
}
}
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 400 | bad_path | The path has .., // or \ | Fix the URL |
| 401 | invalid_key | Missing, unknown, expired or revoked key | Check the key; create a new one |
| 403 | missing_scope | The key lacks the scope | Add the scope (new key) |
| 403 | merchant_inactive | The business's account is not active | The owner checks Billing |
| 404 | not_found | No such record, endpoint, or the feature isn't on for this business | Check the id or path |
| 405 | method_not_allowed | Wrong HTTP method | See the endpoint reference |
| 413 | too_large | Body over 1 MB | Send fewer lines per request |
| 422 | invalid_request | Input failed validation | Read error.fields |
| 429 | rate_limited | Too many requests | Wait Retry-After seconds |
| 500 | server_error | Something failed on our side | Retry with backoff; quote X-Request-Id to support |
| 502 / 504 | upstream_unavailable / upstream_timeout | Briefly unavailable or slow (30 s limit) | Retry with backoff |
Rate limits
Each key has its own limit per minute (120 by default, up to 1,200). Every response carries:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed per minute for this key |
X-RateLimit-Remaining | Requests left in this minute |
Retry-After | On a 429: seconds until you can try again |
There is also a ceiling of 600 requests per minute per client address. To stay well under the limits, sync with updated_since instead of re-reading everything, use per_page=200, and react to webhooks instead of polling.
Retrying safely
GET requests can always be retried. A POST that timed out may still have worked: before sending it again, look the record up (for example GET /customers?email=…) so you don't create it twice.
Request ids and CORS
Every response has an X-Request-Id. Log it — support can find the exact request from it. CORS is open, but keys must stay on your server; call the API from your back end, not from browser code.
Still stuck? Email support@leisurenexus.com or send us a message — we're happy to help.