Overview
Duffel uses standard HTTP response codes to indicate the success or failure of API requests.
Status code
Code | Reason | Description |
---|---|---|
200 | OK | The request was successful |
201 | Created | The request was successful, and a new resource was created |
202 | Accepted | The request was successful, but the processing hasn't been completed |
204 | No Content | The request was successful, but there is no response to send back |
400 | Bad Request | The request was invalid, for example due to missing headers |
401 | Unauthorized | An access token wasn't provided, or the provided token was invalid |
403 | Forbidden | A valid access token was provided, but it didn't have sufficient permissions |
404 | Not Found | The requested resource doesn't exist |
406 | Not Acceptable | The response type you requested with your Accept header isn't supported |
422 | Unprocessable Entity | A validation error occurred |
429 | Too Many Requests | You made too many requests to the API in a short period of time |
500 | Internal Server Error | Something went wrong. Please contact our support team and attach the request_id to your message. You should not retry this request. |
502 | Bad Gateway | Bad gateway error. Please contact our support team and attach the request_id to your message. You should not retry this request. |
503 | Service Unavailable | There is a temporary issue with the server. If the error persists please contact our support team and attach the request_id to your message. Please retry later. |
504 | Gateway Timeout | Gateway timeout error. If the error persists please contact our support team and attach the request_id to your message. Please retry later. |
Errors
Error responses
Detailed information on what exactly went wrong will be included in the response body.
Every error returned by the API includes:
Name | Description |
---|---|
title | A quick and simple description of what went wrong |
message | A more detailed human-readable description of what went wrong |
documentation_url | A URL pointing to a place in our documentation where you can read about the error |
type | A machine-readable identifier for the general category of error |
code | A machine-readable identifier for this specific error |
Error types
An error’s
type
is an enum of the following values:Name | Description |
---|---|
authentication_error | There was a problem with authenticating you - for example, you didn't provide an access token or it was invalid |
airline_error | We've received an error back from the airline - for example, your booking has already been cancelled |
invalid_state_error | You tried to perform an action on a resource that wasn't appropriate - for example, you tried to create an order with an offer that is no longer available |
rate_limit_error | You made too many requests to the API in a short period of time |
validation_error | You didn't provide a required parameter or a parameter you provided was invalid - for example, you didn't specify slices when creating an offer request |
invalid_request_error | There was some other kind of problem with your request - for example, you requested a resource that doesn't exist or missed out a required header |
api_error | Something went wrong on our side, and has been reported to us |
Error codes
An error's
code
is an enum of the following values:Value | Description |
---|---|
access_token_not_found | The access token used is not recognized by our system |
airline_internal | The airline has responded with an internal error, please contact support |
airline_unknown | The airline responded with an unexpected error, please contact support |
ancillary_service_not_available | Requested ancillary service item(s) (e.g. seats) are no longer available, please update your requested services or create a new offer request |
already_cancelled | The provided order has already been cancelled |
bad_request | The request was unacceptable |
booking_already_attempted | A booking has already been attempted for this rate and is pending. If confirmed, a webhook will follow. If unsuccessful, support will contact you. |
booking_already_confirmed | A booking has already been confirmed for this rate. A webhook notification will follow. |
cannot_pay_with_card | You cannot pay with a card for this Stays quote, retry the request without a card ID |
card_expires_before_check_in | The card provided expires before the check-in date of the Stays booking, try a different card that expires at least month after the check in date |
card_missing | You must provide a card ID to book the Stays quote |
card_not_found | The card ID provided to book the Stays quote was not found |
card_payment_not_supported | Card payments are not supported for this Stays rate, select a different rate |
card_type_not_accepted | The card type or brand of the provided card was not accepted to book the Stays quote, select a different rate or try a different card brand |
duplicate_booking | A booking with the same details was already found for the selected itinerary, please select another offer |
duplicate_passenger_name | The order cannot contain more than one passenger with the same name |
expired_access_token | The provided access token has expired |
insufficient_balance | There wasn't enough balance in the wallet for the operation - for example, you booked a flight for £300 with only £200 available in the wallet |
insufficient_permissions | The provided token doesn't have sufficient permissions to perform the requested action |
internal_server_error | There was something wrong on our end, please contact support |
invalid_authorization_header | The Authorization header must conform to the following format: Bearer API_TOKEN |
invalid_content_type_header | The Content-Type should be set to application/json |
invalid_data_param | The data in the request body should be a JSON object |
invalid_email_address | The airline does not support the format of the email address provided |
invalid_field_sets | The request had an invalid combination of fields |
invalid_loyalty_card | The airline did not recognise the loyalty programme account details for one or more of the passengers |
invalid_passenger_title | The title of one of the passengers is not valid |
invalid_payment_details | The payment details which have been provided are not valid |
invalid_phone_number | The phone number is not valid |
invalid_request | The provided request is not valid |
invalid_version_header | The Duffel-Version header must be a known version of our API as indicated in our Docs |
loyalty_programme_required | The Stays quote you are trying to book is only available to members of supported loyalty programme. Retry the booking with loyalty programme information |
loyalty_programme_unsupported | The Stays quote you are trying to book does not support loyalty programme. Retry the booking with no loyalty programme information |
malformed_data_param | The data in the request body is not valid |
missing_authorization_header | The Authorization header must be set and contain a valid API token |
missing_content_type_header | The Content-Type header needs to be set to application/json |
missing_data_param | The data in the request body should be nested under the data key |
missing_version_header | The Duffel-Version header is required and must be a valid API version |
new_airline_initiated_change | There is a new change to your order. Please try again later |
not_found | The resource you are trying to access does not exist |
offer_expired | The selected offer has already expired |
offer_no_longer_available | The provided offer is no longer available, please select another offer or create a new offer request to get the latest availability |
offer_request_already_booked | An offer from this offer request has already been booked; please perform a new search |
order_change_already_actioned | The order change has already been actioned and cannot be actioned again |
order_creation_already_attempted | Order creation has already been attempted for the provided offer. You should not retry this request |
order_not_created | The request to create an order was not successful. You should not retry this request |
order_not_changeable | This order cannot be changed through the API |
payment_amount_does_not_match_order_amount | The amount provided in the payment does not match the total_amount of the order |
payment_currency_does_not_match_order_currency | The currency provided in the payment does not match the total_currency of the order |
payment_declined | The payment was declined, please try again with a different payment method |
price_changed | The provided offer is no longer available for the same price, please retrieve the offer again to get the latest pricing information. |
result_no_longer_available | The Stays search result is no longer available, please perform a new search to get the latest availability |
rate_limit_exceeded | Too many requests have hit the API too quickly. Please retry your request after the time specified in the ratelimit-reset header returned to you |
rate_unavailable | The Stays rate for the selected accommodation is no longer available, please select another rate or do a new search to get the latest availability |
stale_airline_initiated_change_accept | The change you tried to accept is not the latest. Please retry the request with the latest one |
stale_airline_initiated_change_update | The change you tried to update is not the latest. Please retry the request with the latest one |
unavailable_feature | The feature you requested is not available. Please contact help@duffel.com if you are interested in getting access to it |
unsupported_action | The resource does not support the following action |
unsupported_format | The API does not support the format set in the Accept header, please use a supported format |
unsupported_version | The version set to the Duffel-Version header is no longer supported by the API, please upgrade |
validation_checksum | The credit card number provided is not valid |
validation_format | The field submitted has an invalid format |
validation_inclusion | The field submitted must be one of a fixed set of values |
validation_length | The length of the submitted field is out of the boundaries for that field |
validation_required | The field submitted cannot be blank |
validation_type | The field submitted has an invalid type |
validation_unique | The field submitted must be unique |
Examples
If you don't provide an authorization header in your request, you'll receive an
authentication_error
like the following:{"errors": [{"code": "missing_authorization_header","documentation_url": "https://duffel.com/docs/api/overview/response-handling","message": "The 'Authorization' header needs to be set and contain a valid API token.","title": "Missing authorization header","type": "authentication_error"}],"meta": {"request_id": "FZW0H3HdJwKk5HMAAKxB","status": 401}}
If you don't provide a required parameter, or some data you provided is invalid, you'll receive a validation error, with a
type
of validation_error
. Validation errors include an additional source
property, pointing to the exact field in your request which was invalid. Here's an example of a validation error returned when a slice in an offer request doesn't have an origin:{"errors": [{"code": "validation_required","documentation_url": "https://duffel.com/docs/api/overview/response-handling","message": "Field 'origin' can't be blank","source": {"field": "origin","pointer": "/slices/0/origin"},"title": "Required field","type": "validation_error"}],"meta": {"request_id": "FZW0cz5rZoJSEekAAK2B","status": 422}}
Error cases guidelines
Some common error cases and possibly misleading scenarios that can happen and how to react to them.
Expired offers
One of the common errors that can be received while creating an order is
offer_expired
. This error indicates that the selected offer has expired on the Duffel platform and cannot be used to create an order.If an
offer_expired
error is received while creating an order, the request should not be retried and a new search should be performed and the resulting offers used instead.Additionally, the
expires_at
attribute can be used to ensure that order creation requests are not attempted with expired offers. Every offer contains an expires_at
attribute that indicates how long it is valid for (usually 15 - 30 minutes from creation).{"data": {..."expires_at": "2020-01-17T10:42:14.545Z",...}}
Duffel recommends pre-validation of the
expires_at
attribute of an offer - ensuring it is in the future - before performing an order creation request.Validation errors
Validation errors refer to invalid inputs or errors in the format expected of a field in the request. They contain a description of the issue in the response field
message
and require an adjustment to the request for it to succeed. See error types for more information on the different validation errors that can be seen.Temporary errors
Temporary errors are returned when a transient issue has occurred, either within Duffel or on one of our airlines' platforms. They are safe to retry and should generally work on subsequent attempts.
If these errors are persistent, check Duffel Status or contact support for help.
Passenger age vs. Type mismatches
Some airlines expect an alignment of the passenger types between searching and booking flights. When this misalignment is detected by the airline, a response that indicates a lack of availability is returned and Duffel returns an
offer_no_longer_available
error.While it is tricky to determine if this misalignment is the cause of a specific
offer_no_longer_available
error, the circumstances which generate this misalignment can be easily mitigated by passing in an age instead of type for each passenger when performing searches.Although Duffel offers the ability to specify passengers in an offer request with a type (e.g.
adult
, child
, infant_without_seat
), airlines have varying polices and rules on how to interpret these types. As a result of these variations, there can be occasional mismatches between the passenger types in the search and the eventual order creation.{"data": {"passengers": [{"type": "child"}]}}
To avoid this mismatch between searching and order creation, Duffel recommends to specify the age (e.g. 18) of a passenger when creating offer requests.
{"data": {"passengers": [{"age": 13}]}}
Order and booking creation
When you submit a Create Flights Order or Create Stays Booking request to Duffel, it initiates the reservation and payment process for your travel services. As money changing hands as part of this request, it is important you handle the responses correctly as the transactions is usually non-refundable. This section outlines the possible responses and how you should handle them.
201 Created
The request was successful, and a new resource was created. You’ll get the complete resource information, including the resource
id
, e.g. ord_00009hthhsUZ8W4LxQgkjo
for Flights Orders, or bok_0000BTVRuKZTavzrZDJ4cb
for Stays Bookings.
You can retrieve the resource information from the Duffel API, and it will be also visible on the Duffel Dashboard. Check the endpoints’ documentation for detailed information about their response schemas.200 Successful
The request was successful, and a new resource has not yet been created. You’ll get a message that a booking was made in the supplier system. However, it wasn’t possible to retrieve complete information about the booking during the initial booking request. You will be able to retrieve the resource information from the Duffel API, and visible on the Duffel Dashboard once the resource is created.
This response only occurs when you make a Create Flights Order with payments.type of
card
. For Create Stays Booking this response may occur for any payment type.Here is an example:
{"data": {"message": "The booking has been confirmed. It will appear in the system soon."}}
There are two methods to retrieve the complete booking information, webhooks or listing bookings.
Duffel sends Webhook notifications to keep you informed about the status and details of your created resources. You will receive a notification on your Webhook immediately when the resource information is available on the Duffel System. The notifications will contain the information that you need to match the resources you attempted to create to the reservation and to get the complete information.
To get notified about the created object, you must set up webhooks and listen to the events
order.created
for Duffel Flights and stays.booking.created
for Duffel Stays.You can also check manually if the resource was created using the Duffel listing APIs or accessing the Duffel dashboard.
The resource might take a couple of hours to show up on the Duffel API, so it’s important that you assure the traveller that their reservation was successful.
Flights
You will receive a
order.created
webhook notification when the order is created. The webhook notification will contain the offer_id
and the order_id
.Stays
You will receive a
stays.booking.created
notification when the booking is created. The webhook notification will contain the quote_id
and the booking_id
You will also receive an email to your support contact email address configured via the dashboard.202 Accepted
The request was accepted and we are working to confirm its outcome.
When you make a Create Flights Order request, this response can only occur with payments.type of
card
. When you make a Create Stays Booking request, this response may occur for any payment type.Flights
You will receive a webhook notification to inform you on the result of your request if it was successful and resulted in an order being created. If the request did not result in an order, you will receive a notification email from our support team, advising you of this, to your support contact email address configured via the dashboard.
Stays
You will receive a
stays.booking.created
notification if the booking was successfully created. If the request did not result in a booking, you will receive a stays.booking_creation_failed
webhook notification. In either case, you will also receive a notification email from our support team, advising you of the outcome, to your support contact email address configured via the dashboard.Please see our webhooks implementation guide for more information on receiving webhook notifications.
4XX Request Errors
There’s a problem in your request. There can be many reasons, from a malformed request (e.g. invalid JSON), invalid value in a request key (e.g. namer with integer number), or a problem with a resource (e.g. offer is expired). You should check Status Code and Errors sections for the most common errors and how to handle them.
503 Service Unavailable
There’s an unexpected temporary problem. We know for sure that no booking was created in the supplier systems. This indicates you can retry the request again at another time or start another search.
If the error persists, you should contact our support team and attach the
request_id
to your message.500 Internal Server Error
An unexpected problem has occurred. This is often due to a temporary issue on the supplier systems. Regardless of the cause of the issue, we actively monitor such failures and will promptly investigate, address, and mitigate these issues, or reach out to our customers to provide a workaround.
If you consistently encounter this error with a specific request, don't hesitate to contact our support team for more details on the failed attempt. Remember to include the
request_id
, as well as the id
of the resource you're trying to create (the offer id
for Duffel Flights, or quote id
for Duffel Stays) in your message.Rate limiting
If you send too many API requests in quick succession, you'll receive a
rate_limit_error
like the following:{"errors": [{"code": "rate_limit_exceeded","documentation_url": "https://duffel.com/docs/api/overview/response-handling","message": "Too many requests hit the API too quickly. Please retry your request after the time specified in the `ratelimit-reset` header.","title": "Rate limit exceeded","type": "rate_limit_error"}],"meta": {"request_id": "Fkpj57Fn-uB9b0kAANVI","status": 429}}
You'll also receive information about the rate limiting which was applied to your request in the HTTP headers which are returned as part of the response:
ratelimit-limit: 60
This is the limit of requests you can make per interval period. This period is currently set to 60 seconds but is subject to change without notice. If you feel that you may require a larger quota than this, drop us a line.
ratelimit-remaining: 0
This is the amount of requests you can still make during the current period before being rate limited.
ratelimit-reset: Tue, 24 Nov 2020 08:22:00 GMT
This is when your rate limit will be reset, in an RFC 2616 compliant human readable format.