Error Handling
All API responses use a consistent envelope format. See Core Concepts for the full structure. This page focuses on error categories, retry strategies, and how to handle common error scenarios.
Error Categories
4xx Client Errors
Errors caused by invalid requests. Fix the request before retrying.
| HTTP Status | Error Code | Meaning | Solution |
|---|---|---|---|
| 400 | INVALID_REQUEST | Validation failed | Check error.details for field-specific errors |
| 400 | INVALID_LOCATION | Invalid location provided | Check location format or use valid locationId |
| 400 | INVALID_DATE_RANGE | Date range is invalid | Ensure pickup is before return, dates in future |
| 400 | INVALID_OFFER_TOKEN | Token format invalid/corrupted | Get fresh offer token from search/prebook |
| 400 | MISSING_REQUIRED_FIELD | Required field not provided | Check error.details for missing fields |
| 401 | UNAUTHORIZED | Invalid/expired token | Refresh API token |
| 401 | AUTHENTICATION_REQUIRED | Missing Authorization header | Add Bearer token |
| 403 | FORBIDDEN | Insufficient permissions | Contact support for access |
| 404 | NOT_FOUND | Resource doesn't exist | Verify resource ID |
| 404 | NO_OFFERS_AVAILABLE | No offers match criteria | Broaden search dates/locations |
| 409 | OFFER_EXPIRED | Offer token expired | Start new search |
| 409 | OFFER_EXPIRED | Offer sold out | Show alternative offers |
| 409 | OFFER_TOKEN_ALREADY_USED | Token was already used | Get fresh offer token from search/prebook |
| 409 | MISSING_REQUIRED_FIELD | Provider needs additional fields | Collect information, retry with same token |
| 409 | BOOKING_FAILED | Booking could not be created | Check error details, may need new search |
| 422 | INVALID_REQUEST | Invalid field values | Fix validation errors in details |
| 429 | RATE_LIMIT_EXCEEDED | Too many requests | Wait and retry with backoff |
5xx Server Errors
Temporary server issues. Safe to retry with exponential backoff.
| HTTP Status | Error Code | Meaning | Solution |
|---|---|---|---|
| 500 | INTERNAL_ERROR | Server error | Retry with backoff |
| 500 | PROVIDER_ERROR | Provider returned error | Retry with backoff |
| 501 | OPERATION_NOT_SUPPORTED | Feature not supported | Use alternative endpoint/provider |
| 503 | SERVICE_UNAVAILABLE | Temporary outage | Retry after delay |
| 504 | TIMEOUT | Operation timed out | Retry with backoff |
Field Validation Errors
When you receive an INVALID_REQUEST, the error.details object contains field-specific issues that you can map directly to your form fields:
{
"success": false,
"error": {
"code": "INVALID_REQUEST",
"message": "Request validation failed",
"details": {
"origin.dateTime": "Must be in the future",
"destination.dateTime": "Must be after origin time"
}
}
}
Parse the keys in error.details to identify which fields need correction and display inline validation messages to the user. Do not retry until the user has fixed the input.
Retry Strategy
Network errors, 5xx server errors, and 429 rate limit responses are safe to retry. Use exponential backoff starting at 1 second and doubling with each attempt (1s, 2s, 4s, 8s), with a maximum of 3-5 retries. Add a small random jitter (0-1 second) to each wait to prevent thundering herd effects when multiple clients retry simultaneously. The MISSING_REQUIRED_FIELD error is also retryable after you have collected the required fields from the user.
Do not retry authentication errors (401, 403), validation errors (400, 422), not found errors (404), or business logic errors like OFFER_EXPIRED and OFFER_TOKEN_ALREADY_USED. These require either fixing the request, obtaining fresh data, or informing the user.
Common Scenarios
Expired Offer Token
When you receive OFFER_EXPIRED, the user took too long to complete the booking flow and the token's validity window has passed. Do not retry with the same token. Instead, guide the user back to search with a message like "This offer has expired. Please search again for current availability and pricing." Displaying the usableUntil timestamp as a countdown in your UI can help users complete the flow before expiration.
Offer Token Already Used (Idempotency)
The OFFER_TOKEN_ALREADY_USED error means a booking was already successfully created with this token. This is the API's built-in idempotency mechanism — each prebooked offer token can only produce one booking.
This error only occurs if a booking was already created. If previous requests failed with network or server errors, the token is still valid and you can safely retry.
This commonly happens when a network timeout occurs during booking creation but the booking actually succeeded on the server, or when the user accidentally submits the form twice. When you receive this error, query the bookings endpoint to retrieve the booking details and show the user their confirmation. Display a message like "A booking has already been created. Please check your bookings or contact support with request ID: {requestId}."
For handling booking failures in general: retry with the same token on network/server errors (5xx, timeout), check the bookings endpoint on OFFER_TOKEN_ALREADY_USED, and obtain a fresh token from search/prebook on OFFER_EXPIRED or other errors.
Offer No Longer Available
The OFFER_EXPIRED error indicates another user booked the last available option. Show alternative offers from the existing search results if available, or suggest the user search again with nearby locations or adjusted dates. A message like "This option is no longer available. Here are similar alternatives..." provides a good experience.
Rate Limiting
When RATE_LIMIT_EXCEEDED is returned, check the X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset response headers to determine when you can retry. If these headers are absent, fall back to exponential backoff. Caching search results locally helps reduce API call volume and avoid hitting rate limits. Show users a message like "Please wait a moment before searching again."
Additional Information Required
The MISSING_REQUIRED_FIELD error means a provider needs data that was not part of the initial request. The error.details.requiredFields array describes what is needed, with each entry specifying a field name, type (boolean or string), label, and message.
{
"success": false,
"error": {
"code": "MISSING_REQUIRED_FIELD",
"message": "Additional information needed",
"details": {
"requiredFields": [
{
"field": "MULTIPLE_BOOKINGS_CONFIRMATION",
"type": "boolean",
"label": "Confirm multiple bookings",
"message": "More than one booking on one card. Accept?"
},
{
"field": "FLIGHT_NUMBER",
"type": "string",
"label": "Flight number",
"message": "Please provide your arrival flight number"
}
],
"retryable": true
}
}
}
For boolean fields, display a checkbox or confirmation prompt with the message. For string fields, display a text input with the label. Once you have collected the information, retry the request with the same prebookedOfferToken plus the additional data. The prebook reservation remains valid during this process. Common examples include confirming multiple bookings on a single customer card (Stadtmobil), providing a flight number for airport pickups, or supplying a driver license number for certain vehicle classes.
Timeout Handling
Different operations have different latency characteristics due to the multi-provider architecture:
| Operation | Expected Duration | Recommended Timeout |
|---|---|---|
| Search | 1-20 seconds | 25 seconds |
| Offer Details | 2-5 seconds | 10 seconds |
| Prebook | 3-8 seconds | 15 seconds |
| Create Booking | 5-15 seconds | 30 seconds |
Show loading indicators with a spinner during long operations, especially searches and booking creation.
Logging
Log every error response together with the meta.requestId, the error code and message, what the user was trying to do, and any relevant booking or offer IDs. When contacting support, include the requestId along with the error code, the user's action, and a timestamp — this allows us to trace the request through our systems quickly.