Errors

Duffel uses standard HTTP response codes to indicate the success or failure of API requests.

Status codes

CodeReasonDescription
200OKThe request was successful
201CreatedThe request was successful, and a new resource was created
204No ContentThe request was successful, but there is no response to send back
400Bad RequestThe request was invalid, for example due to missing headers
401UnauthorizedAn access token wasn't provided, or the provided token was invalid
403ForbiddenA valid access token was provided, but it didn't have sufficient permissions
404Not FoundThe requested resource doesn't exist
406Not AcceptableThe response type you requested with your Accept header isn't supported
422Unprocessable EntityA validation error occurred
429Too Many RequestsYou made too many requests to the API in a short period of time
500Internal Server ErrorSomething went wrong. Please contact our support team and attach the request_id to your message. You should not retry this request.
502Bad GatewayBad gateway error. Please contact our support team and attach the request_id to your message. You should not retry this request.
503Service UnavailableThere 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.
504Gateway TimeoutGateway 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:

NameDescription
titleA quick and simple description of what went wrong
messageA more detailed human-readable description of what went wrong
documentation_urlA URL pointing to a place in our documentation where you can read about the error
typeA machine-readable identifier for the general category of error
codeA machine-readable identifier for this specific error

Error types

An error’s type is an enum of the following values:

NameDescription
authentication_errorThere was a problem with authenticating you - for example, you didn't provide an access token or it was invalid
airline_errorWe've received an error back from the airline - for example, your booking has already been cancelled
invalid_state_errorYou 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_errorYou made too many requests to the API in a short period of time
validation_errorYou 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_errorThere 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_errorSomething 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_foundThe access token used is not recognized by our system
airline_internalThe airline has responded with an internal error, please contact support
airline_unknownThe airline responded with an unexpected error, please contact support
ancillary_service_not_availableRequested ancillary service item(s) (e.g. seats) are no longer available, please update your requested services or create a new offer request
already_cancelledThe provided order has already been cancelled
bad_requestThe request was unacceptable
duplicate_bookingA booking with the same details was already found for the selected itinerary, please select another offer
duplicate_passenger_nameThe order cannot contain more than one passenger with the same name
expired_access_tokenThe provided access token has expired
insufficient_balanceThere 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_permissionsThe provided token doesn't have sufficient permissions to perform the requested action
internal_server_errorThere was something wrong on our end, please contact support
invalid_authorization_headerThe Authorization header must conform to the following format: Bearer API_TOKEN
invalid_content_type_headerThe Content-Type should be set to application/json
invalid_data_paramThe data in the request body should be a JSON object
invalid_email_addressThe airline does not support the format of the email address provided.
invalid_loyalty_cardThe airline did not recognise the loyalty programme account details for one or more of the passengers
invalid_passenger_titleThe title of one of the passengers is not valid
invalid_phone_numberThe phone number is not valid
invalid_version_headerThe Duffel-Version header must be a known version of our API as indicated in our Docs
malformed_data_paramThe data in the request body is not valid
missing_authorization_headerThe Authorization header must be set and contain a valid API token
missing_content_type_headerThe Content-Type header needs to be set to application/json
missing_data_paramThe data in the request body should be nested under the data key
missing_version_headerThe Duffel-Version header is required and must be a valid API version
new_airline_initiated_changeThere is a new change to your order. Please try again later
not_foundThe resource you are trying to access does not exist
offer_expiredThe selected offer has already expired
offer_no_longer_availableThe provided offer is no longer available, please select another offer or create a new offer request to get the latest availability
offer_request_already_bookedAn offer from this offer request has already been booked; please perform a new search
order_change_already_actionedThe order change has already been actioned and cannot be actioned again
order_creation_already_attemptedOrder creation has already been attempted for the provided offer. You should not retry this request.
order_not_createdThe request to create an order was not successful. You should not retry this request.
payment_amount_does_not_match_order_amountThe amount provided in the payment does not match the total_amount of the order
payment_currency_does_not_match_order_currencyThe currency provided in the payment does not match the total_currency of the order
rate_limit_exceededToo many requests have hit the API too quickly. Please retry your request after the time specified in the ratelimit-reset header returned to you
stale_airline_initiated_change_acceptThe change you tried to accept is not the latest. Please retry the request with the latest one
stale_airline_initiated_change_updateThe change you tried to update is not the latest. Please retry the request with the latest one
unavailable_featureThe feature you requested is not available. Please contact help@duffel.com if you are interested in getting access to it
unsupported_actionThe resource does not support the following action
unsupported_formatThe API does not support the format set in the Accept header, please use a supported format
unsupported_versionThe version set to the Duffel-Version header is no longer supported by the API, please upgrade
validation_checksumThe credit card number provided is not valid
validation_formatThe field submitted has an invalid format
validation_inclusionThe field submitted must be one of a fixed set of values
validation_lengthThe length of the submitted field is out of the boundaries for that field
validation_requiredThe field submitted cannot be blank
validation_typeThe field submitted has an invalid type
validation_uniqueThe 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/errors",
"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/errors",
"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
}
]
}
}

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/errors",
"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.