Error Codes
Error codes, retryability and error handling guide.
Overview#
All Bokko Public API responses use a consistent envelope format, regardless of whether the request was successful or not. The golden rule for error handling:
- Always branch based on the
error.codefield. - Never programmatically interpret the
error.messagetext.
error.message field can change at any time and may be localized (in Hungarian). Do not build logic on it -- only the error.code field is stable and contractual.Response Format#
Successful Response#
{ ... } are placeholders, not valid JSON. The actual content of the data field varies by endpoint; for specific examples, see the Quickstart page.{
"ok": true,
"data": { ... },
"meta": { "requestId": "req_01HX...", "v": "1" }
}Error Response#
{
"ok": false,
"error": {
"code": "booking.slot_unavailable",
"message": "The selected time slot is no longer available.",
"retryable": false,
"details": {
"requestedDate": "2026-04-05",
"requestedStartTime": "10:00",
"nextAvailableStartTime": "10:45"
}
},
"meta": { "requestId": "req_01HX...", "v": "1" }
}The details field is optional and contains error-code-specific structures. It is only present when the error requires further context.
Error Code Structure#
Error codes follow the {domain}.{reason} format:
| Domain | Example | Description |
|---|---|---|
auth | auth.invalid_key | Authentication and authorization errors |
booking | booking.slot_unavailable | Booking logic errors |
request | request.invalid_input | Input validation and request errors |
rate_limit | rate_limit.exceeded | Rate limit exceeded |
idempotency | idempotency.payload_mismatch | Idempotency key collision |
service | service.not_found | Resource not found |
internal | internal.error | Internal system error (5xx) |
The code field is stable -- it does not change during the lifetime of the API version. The message field is intended exclusively for human reading.
Retryability#
Every error response includes a retryable boolean field, which indicates whether the request can be resent without changes.
| Error Code | retryable | Action |
|---|---|---|
rate_limit.exceeded | true | Wait for the time indicated in the Retry-After header, then try again. |
idempotency.request_in_progress | true | The original request is still being processed -- wait and then try again. |
internal.error (5xx) | true | Internal error — try again with exponential backoff; include the requestId. |
| Everything else | false | Fix the request; do not blindly try again. |
Exponential Backoff:
1st attempt: immediate
2nd attempt: 1s wait
3rd attempt: 2s wait
4th attempt: 4s wait
(max 3 retries)If the response includes a Retry-After header, its value takes precedence over backoff logic.
Debugging#
Every response contains a meta.requestId field that uniquely identifies the request.
requestId and include it with support requests. This allows the exact tracing of the request within the system.Using requestId:
- Correlation with webhook delivery logs.
- Precise error identification for support requests.
- Chronological reconstruction across multiple requests.
Common HTTP Status Codes#
| Status | Meaning | Recommended Step |
|---|---|---|
400 | Invalid input or schema error | Check the request body based on the details field; fix and try again. |
401 | Invalid or missing API key | Check the key format (bk_live_...) and status on the dashboard. |
403 | Permission denied | Check the key's capability set and the salonSlug match. |
404 | Resource not found | Check the URL and the resource identifier. |
409 | Conflict | Check the booking status or time slot availability. |
429 | Rate limit exceeded | Adhere to the Retry-After header, reduce request frequency. |
500 | Internal error | Not your fault -- try again later, or report it with the requestId. |
Error Code Catalog#
Hitelesítési hibák (auth.*)
| Kód | HTTP | Retryable | Leírás |
|---|---|---|---|
auth.invalid_key | 401 | ❌ Nem | Hiányzó vagy érvénytelen API kulcs |
auth.insufficient_capability | 403 | ❌ Nem | A kulcs nem rendelkezik a szükséges capability-vel Details: { required, granted } |
auth.scope_mismatch | 403 | ❌ Nem | A salonSlug nem egyezik a kulcs tenant scope-jával |
auth.plan_insufficient | 403 | ❌ Nem | Az aktív előfizetés nem tartalmazza a Public API hozzáférést (Pro csomag szükséges) |
Kérési hibák (request.*)
| Kód | HTTP | Retryable | Leírás |
|---|---|---|---|
request.invalid_input | 400 | ❌ Nem | Séma validáció sikertelen Details: { fieldErrors: [{ field, reason }] } |
request.invalid_cursor | 400 | ❌ Nem | Érvénytelen vagy lejárt cursor |
request.missing_idempotency_key | 400 | ❌ Nem | Idempotency-Key header hiányzik |
request.not_found | 404 | ❌ Nem | Az endpoint nem létezik |
request.method_not_allowed | 405 | ❌ Nem | Nem engedélyezett HTTP metódus |
Foglalási hibák (booking.*)
| Kód | HTTP | Retryable | Leírás |
|---|---|---|---|
booking.slot_unavailable | 409 | ❌ Nem | A kért időpont már nem elérhető Details: { requestedDate, requestedStartTime, nextAvailableStartTime } |
booking.not_found | 404 | ❌ Nem | Foglalás nem található |
booking.invalid_transition | 409 | ❌ Nem | A foglalás terminális állapotban van Details: { currentStatus, attemptedTransition } |
booking.booking_disabled | 409 | ❌ Nem | Online foglalás nincs engedélyezve |
booking.booking_restricted | 409 | ❌ Nem | Foglalás átmenetileg korlátozva |
booking.service_pricing_changed | 409 | ❌ Nem | A szolgáltatás ára változott a megerősítés óta — kérj friss listát Details: { currentPricingVersion } |
Idempotencia hibák (idempotency.*)
| Kód | HTTP | Retryable | Leírás |
|---|---|---|---|
idempotency.payload_mismatch | 409 | ❌ Nem | Ugyanaz a kulcs, de eltérő payload |
idempotency.request_in_progress | 503 | ✅ Igen | A kérés még feldolgozás alatt áll |
Rate limit (rate_limit.*)
| Kód | HTTP | Retryable | Leírás |
|---|---|---|---|
rate_limit.exceeded | 429 | ✅ Igen | Rate limit túllépve Details: { retryAfterSeconds } |
Elérhetőség (availability.*)
| Kód | HTTP | Retryable | Leírás |
|---|---|---|---|
availability.date_range_too_wide | 400 | ❌ Nem | Dátumtartomány túl széles Details: { maxDays: 31 } |
Szolgáltatás (service.*)
| Kód | HTTP | Retryable | Leírás |
|---|---|---|---|
service.not_found | 404 | ❌ Nem | Ismeretlen serviceId |
service.unavailable | 409 | ❌ Nem | A szolgáltatás jelenleg nem elérhető (deactivated vagy archive-ban) Details: { serviceId } |
service.not_bookable | 409 | ❌ Nem | A szolgáltatás nem online foglalható (onlineBookable=false) Details: { serviceId } |
Szolgáltató (salon.*)
| Kód | HTTP | Retryable | Leírás |
|---|---|---|---|
salon.not_found | 404 | ❌ Nem | Szolgáltató nem található |
Webhook (webhook.*)
| Kód | HTTP | Retryable | Leírás |
|---|---|---|---|
webhook.not_found | 404 | ❌ Nem | Webhook konfiguráció nem található |
Előfizetés (subscription.*)
| Kód | HTTP | Retryable | Leírás |
|---|---|---|---|
subscription.not_found | 404 | ❌ Nem | Az előfizetés még nem aktivált (pre-activation állapot, nem kliens hiba) |
subscription.snapshot_missing | 500 | ❌ Nem | Belső invariáns sérülés — szerver-oldali alert |
Belső hiba (internal.*)
| Kód | HTTP | Retryable | Leírás |
|---|---|---|---|
internal.error | 500 | ✅ Igen | Belső szerverhiba — generic fallback. Próbáld újra később, vagy jelezd a requestId-vel. |