Errors & Rate Limits
Status codes, error shapes, throttling, and retries.
Error shape
Validation errors:
{
"message": "The check in field is required.",
"errors": { "check_in": ["The check in field is required."] }
}Everything else returns a message, sometimes with an error or code:
{ "message": "Invalid or expired API key." }Status codes
| Status | When | Do |
|---|---|---|
200 | Success. | |
201 | Prebook created. | Keep the booking id. |
401 | Missing / bad / revoked / expired key. | Check the header; rotate if needed. |
402 | Payment needs action or failed. | See below. |
403 | Test key tried to book. | Use a live key. |
404 | Not found, or belongs to another org. | Check the ID. |
415 | Body wasn't JSON. | Send Content-Type: application/json. |
422 | Validation failed. | Read errors, fix the request. |
429 | Rate limited. | Back off and retry. |
Payment errors
Both come back as 402.
Needs 3-D Secure:
{ "error": "payment_requires_action", "payment_intent_id": "pi_...", "client_secret": "pi_..._secret" }Finish authentication with Stripe.js, then call book again with payment_intent_id. See Book a Package.
Failed:
{ "error": "payment_failed", "message": "Your card was declined." }The message is safe to show for card declines. Retry with a different method.
Rate limits
120 requests per minute per key. Over that, you get 429 with Retry-After, respect it and back off. Need more? Contact support.
Retries
- Book is safe to retry. An already-paid booking is rejected with
422, not charged twice. Intent creation is idempotent per booking. - Prebook is not. Each call creates a new hold. On a timeout, check the booking before retrying.
- On any book timeout, poll the booking to learn the real outcome before retrying.
Updated 4 days ago
Did this page help you?