Docs
Ctrl+K

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.code field.
  • Never programmatically interpret the error.message text.
Figyelmeztetés
The value of the 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#

Info
The block below is a structural illustration — the { ... } are placeholders, not valid JSON. The actual content of the data field varies by endpoint; for specific examples, see the Quickstart page.
json
{
  "ok": true,
  "data": { ... },
  "meta": { "requestId": "req_01HX...", "v": "1" }
}

Error Response#

json
{
  "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:

DomainExampleDescription
authauth.invalid_keyAuthentication and authorization errors
bookingbooking.slot_unavailableBooking logic errors
requestrequest.invalid_inputInput validation and request errors
rate_limitrate_limit.exceededRate limit exceeded
idempotencyidempotency.payload_mismatchIdempotency key collision
serviceservice.not_foundResource not found
internalinternal.errorInternal 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 CoderetryableAction
rate_limit.exceededtrueWait for the time indicated in the Retry-After header, then try again.
idempotency.request_in_progresstrueThe original request is still being processed -- wait and then try again.
internal.error (5xx)trueInternal error — try again with exponential backoff; include the requestId.
Everything elsefalseFix 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.

Tipp
Always save the 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#

StatusMeaningRecommended Step
400Invalid input or schema errorCheck the request body based on the details field; fix and try again.
401Invalid or missing API keyCheck the key format (bk_live_...) and status on the dashboard.
403Permission deniedCheck the key's capability set and the salonSlug match.
404Resource not foundCheck the URL and the resource identifier.
409ConflictCheck the booking status or time slot availability.
429Rate limit exceededAdhere to the Retry-After header, reduce request frequency.
500Internal errorNot your fault -- try again later, or report it with the requestId.

Error Code Catalog#

Hitelesítési hibák (auth.*)

KódHTTPRetryableLeírás
auth.invalid_key401❌ NemHiányzó vagy érvénytelen API kulcs
auth.insufficient_capability403❌ NemA kulcs nem rendelkezik a szükséges capability-vel
Details: { required, granted }
auth.scope_mismatch403❌ NemA salonSlug nem egyezik a kulcs tenant scope-jával
auth.plan_insufficient403❌ NemAz 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ódHTTPRetryableLeírás
request.invalid_input400❌ NemSéma validáció sikertelen
Details: { fieldErrors: [{ field, reason }] }
request.invalid_cursor400❌ NemÉrvénytelen vagy lejárt cursor
request.missing_idempotency_key400❌ NemIdempotency-Key header hiányzik
request.not_found404❌ NemAz endpoint nem létezik
request.method_not_allowed405❌ NemNem engedélyezett HTTP metódus

Foglalási hibák (booking.*)

KódHTTPRetryableLeírás
booking.slot_unavailable409❌ NemA kért időpont már nem elérhető
Details: { requestedDate, requestedStartTime, nextAvailableStartTime }
booking.not_found404❌ NemFoglalás nem található
booking.invalid_transition409❌ NemA foglalás terminális állapotban van
Details: { currentStatus, attemptedTransition }
booking.booking_disabled409❌ NemOnline foglalás nincs engedélyezve
booking.booking_restricted409❌ NemFoglalás átmenetileg korlátozva
booking.service_pricing_changed409❌ NemA szolgáltatás ára változott a megerősítés óta — kérj friss listát
Details: { currentPricingVersion }

Idempotencia hibák (idempotency.*)

KódHTTPRetryableLeírás
idempotency.payload_mismatch409❌ NemUgyanaz a kulcs, de eltérő payload
idempotency.request_in_progress503✅ IgenA kérés még feldolgozás alatt áll

Rate limit (rate_limit.*)

KódHTTPRetryableLeírás
rate_limit.exceeded429✅ IgenRate limit túllépve
Details: { retryAfterSeconds }

Elérhetőség (availability.*)

KódHTTPRetryableLeírás
availability.date_range_too_wide400❌ NemDátumtartomány túl széles
Details: { maxDays: 31 }

Szolgáltatás (service.*)

KódHTTPRetryableLeírás
service.not_found404❌ NemIsmeretlen serviceId
service.unavailable409❌ NemA szolgáltatás jelenleg nem elérhető (deactivated vagy archive-ban)
Details: { serviceId }
service.not_bookable409❌ NemA szolgáltatás nem online foglalható (onlineBookable=false)
Details: { serviceId }

Szolgáltató (salon.*)

KódHTTPRetryableLeírás
salon.not_found404❌ NemSzolgáltató nem található

Webhook (webhook.*)

KódHTTPRetryableLeírás
webhook.not_found404❌ NemWebhook konfiguráció nem található

Előfizetés (subscription.*)

KódHTTPRetryableLeírás
subscription.not_found404❌ NemAz előfizetés még nem aktivált (pre-activation állapot, nem kliens hiba)
subscription.snapshot_missing500❌ NemBelső invariáns sérülés — szerver-oldali alert

Belső hiba (internal.*)

KódHTTPRetryableLeírás
internal.error500✅ IgenBelső szerverhiba — generic fallback. Próbáld újra később, vagy jelezd a requestId-vel.