Webhooks

Webhooks are used to automatically receive notifications of events that happen. For example, when an order has a schedule change.

Once you receive an event on your server, you can process and act on it as you need.

You can manage your webhooks on the Duffel Dashboard.

Events

We'll progressively add more events. The currently supported events are:

  • order.created: This event is sent whenever an order is created. An example response for this event type:

{
"id": "wev_0000A4tQSmKyqOrcySrGbo",
"api_version": "v2",
"type": "order.created",
"data": {
"object": { .. },
},
"live_mode": true,
"idempotency_key": "ord_0000ABd6wggSct7BoraU1o",
"created_at": "2020-04-11T15:48:11.642000Z",
"identity_organisation_id": "org_0000APMFjhs4X2rJ6k7UIE"
}
  • order.creation_failed: This event is sent when creating an order has failed after the order creation request has been accepted but not yet confirmed (202 status code). An example response for this event type:

{
"id": "wev_0000A4tQSmKyqOrcySrGbo",
"api_version": "v2",
"type": "order.creation_failed",
"data": {
"object": { .. },
},
"live_mode": true,
"idempotency_key": "ZmFpbGVkLXBvcl8wMDAwQW5KMjhnQ0lxU3k5RURDeFRV",
"created_at": "2020-04-11T15:48:11.642000Z",
"identity_organisation_id": "org_0000APMFjhs4X2rJ6k7UIE"
}
  • payment.created: This event is sent whenever a payment is created for a hold order. An example response for this event type:

{
"id": "wev_0000A4tQSmKyqOrcySrGbo",
"api_version": "v2",
"type": "payment.created",
"data": {
"object": { .. },
},
"live_mode": true,
"idempotency_key": "pay_0000ABd6wggSct7BoraU1o",
"created_at": "2020-04-11T15:48:11.642000Z",
"identity_organisation_id": "org_0000APMFjhs4X2rJ6k7UIE"
}
{
"id": "wev_0000A4tQSmKyqOrcySrGbo",
"api_version": "v2",
"type": "order.airline_initiated_change_detected",
"data": {
"object": { .. },
},
"live_mode": true,
"idempotency_key": "aic_0011AJSACO83RgsiSySpzH",
"created_at": "2020-03-11T12:18:12.642000Z",
"identity_organisation_id": "org_0000APMFjhs4X2rJ6k7UIE"
}
  • stays.booking.created: This event is sent whenever a Stays booking is created. An example response for this event type:

{
"id": "wev_0000A4tQSmKyqOrcySrGbo",
"api_version": "v2",
"type": "stays.booking.created",
"data": {
"object": { .. },
},
"live_mode": true,
"idempotency_key": "bok_0000AcTKWKVb0RWQOUazJo",
"created_at": "2024-04-18T16:32:11.642000Z",
"identity_organisation_id": "org_0000APMFjhs4X2rJ6k7UIE"
}
  • stays.booking.cancelled: This event is sent whenever a Stays booking is cancelled. An example response for this event type:

{
"id": "wev_0000A4tQSmKyqOrcySrGbo",
"api_version": "v2",
"type": "stays.booking.cancelled",
"data": {
"object": { .. },
},
"live_mode": true,
"idempotency_key": "cancelled-bok_0000AcTKWKVb0RWQOUazJo",
"created_at": "2024-04-18T16:32:11.642000Z",
"identity_organisation_id": "org_0000APMFjhs4X2rJ6k7UIE"
}
  • stays.booking_creation_failed: This event is sent whenever it is unable to create a booking after a Stays booking creation attempt that resulted in a response status code 202.

{
"id": "wev_0000A4tQSmKyqOrcySrGbo",
"api_version": "v2",
"type": "stays.booking_creation_failed",
"data": {
"object": { .. },
},
"live_mode": true,
"idempotency_key": "ZmFpbGVkLWJhdF9vYWthb2FrYWthb2ZBa2RsZGtkMjM=",
"created_at": "2024-10-14T11:49:32.246000Z",
"identity_organisation_id": "org_0000APMFjhs4X2rJ6k7UIE"
}

The api_version represents the version of our API that produced the data property.

System guarantees

Duffel's webhooks system guarantees the following properties:

  • It makes at least one delivery attempt per event.

  • Events are not delivered in any particular order.

  • Events are sent at least once.

  • Failed deliveries are retried for 72 hours on an exponetial backoff policy.

It also has the following security properties:

  • It always makes HTTPS requests.

  • It signs the events.

active
boolean

Whether the webhook receiver is actively being notified or not

Example: true
created_at
datetime

The ISO 8601 datetime at which the webhook was created

Example: "2020-04-11T15:48:11.642Z"
events
string[]

The events that this webhook will be subscribed to

Example: ["order.created","order.airline_initiated_change_detected"]
id
string

Duffel's unique identifier for the webhook receiver

Example: "end_0000A3tQSmKyqOrcySrGbo"
live_mode
boolean

The live mode that the webhook was created in. It will only receive events for that same live mode. For example, you won't receive order.created events for orders that you created in the sandbox, if your webhook is for live_mode: true.

Example: true
updated_at
datetime

The ISO 8601 datetime at which the webhook was updated

Example: "2020-04-11T15:48:11.642Z"
url
string

The URL where your webhook will be received

Example: "https://www.example.com:4000/webhooks"

Send a ping, a "fake event" notification, to a webhook

URL parameters

id
stringrequired

Duffel's unique identifier for the webhook receiver

Example: "end_0000A3tQSmKyqOrcySrGbo"

Endpoint

POST https://api.duffel.com/air/webhooks/{id}/actions/ping

Request

curl -X POST --compressed "https://api.duffel.com/air/webhooks/{id}/actions/ping" \
-H "Accept-Encoding: gzip" \
-H "Accept: application/json" \
-H "Duffel-Version: v2" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>"

Response

No response body

Delete a webhook

URL parameters

id
stringrequired

Duffel's unique identifier for the webhook receiver

Example: "end_0000A3tQSmKyqOrcySrGbo"

Endpoint

DELETE https://api.duffel.com/air/webhooks/{id}

Request

curl -X DELETE --compressed "https://api.duffel.com/air/webhooks/{id}" \
-H "Accept-Encoding: gzip" \
-H "Accept: application/json" \
-H "Duffel-Version: v2" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>"

Response

No response body

Update a webhook

URL parameters

id
stringrequired

Duffel's unique identifier for the webhook receiver

Example: "end_0000A3tQSmKyqOrcySrGbo"

Body parameters

active
boolean

The desired active status of the webhook

Example: true
events
string[]

The desired events that the webhook should subscribe to

Example: ["order.created","order.airline_initiated_change_detected"]
url
string

The desired url of the webhook

Example: "https://example.com/duffel/webhook"

Endpoint

PATCH https://api.duffel.com/air/webhooks/{id}

Request

curl -X PATCH --compressed "https://api.duffel.com/air/webhooks/{id}" \
-H "Accept-Encoding: gzip" \
-H "Accept: application/json" \
-H "Duffel-Version: v2" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>" \
-d '{
"data": {
"url": "https://example.com/duffel/webhook",
"events": [
"order.created",
"order.airline_initiated_change_detected"
],
"active": true
}
}'

Response

{
"data": {
"url": "https://www.example.com:4000/webhooks",
"updated_at": "2020-04-11T15:48:11.642Z",
"live_mode": true,
"id": "end_0000A3tQSmKyqOrcySrGbo",
"events": [
"order.created",
"order.airline_initiated_change_detected"
],
"created_at": "2020-04-11T15:48:11.642Z",
"active": true
}
}

Retrieve a paginated list of webhooks

Query parameters

limit
integer

The maximum number of records to return per page. Defaults to 50. May be set to any integer between 1 and 200. For more information on how to paginate through records, see the Pagination section.

Example: 1
Default value: 50
before
string

A cursor pointing to the next page of records. For more information on how to paginate through records, see the Pagination section.

Example: "g2wAAAACbQAAABBBZXJvbWlzdC1LaGFya2l2bQAAAB="
after
string

A cursor pointing to the previous page of records. For more information on how to paginate through records, see the Pagination section.

Example: "g2wAAAACbQAAABBBZXJvbWlzdC1LaGFya2l2bQAAAB="

Endpoint

GET https://api.duffel.com/air/webhooks

Request

curl -X GET --compressed "https://api.duffel.com/air/webhooks?limit=1&before=g2wAAAACbQAAABBBZXJvbWlzdC1LaGFya2l2bQAAAB=&after=g2wAAAACbQAAABBBZXJvbWlzdC1LaGFya2l2bQAAAB=" \
-H "Accept: application/json" \
-H "Accept-Encoding: gzip" \
-H "Duffel-Version: v2" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>"

Response

{
"meta": {
"limit": 50,
"after": "g2wAAAACbQAAABBBZXJvbWlzdC1LaGFya2l2bQAAAB="
},
"data": [
{
"url": "https://www.example.com:4000/webhooks",
"updated_at": "2020-04-11T15:48:11.642Z",
"live_mode": true,
"id": "end_0000A3tQSmKyqOrcySrGbo",
"events": [
"order.created",
"order.airline_initiated_change_detected"
],
"created_at": "2020-04-11T15:48:11.642Z",
"active": true
}
]
}

To start receiving notifications of events, you'll need to create a webhook that details the server that will receive the notifications. The webhook will be created in live mode or test mode based on the access token you're using. If you're using a test mode access token, the webhook will be created in test mode and will receive events related to test mode resources. If you're using a live mode access token, it'll receive events related to live mode.

Duffel only allows one webhook to be defined per live mode value, basically your organisation can only have one url with live_mode: true and another with live_mode: false.

To ensure the highest level of security we run some checks on the URL we receive, the URL must be for an https server, we do not accept IP addresses and some URLs are blacklisted (e.g. https://localhost).

By default, the webhook will be active.

Body parameters

events
string[]required

The events that this webhook will be subscribed to

Example: ["order.created","order.airline_initiated_change_detected"]
url
stringrequired

The URL where your webhook will be received

Example: "https://www.example.com/webhooks"

Endpoint

POST https://api.duffel.com/air/webhooks

Request

curl -X POST --compressed "https://api.duffel.com/air/webhooks" \
-H "Accept-Encoding: gzip" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Duffel-Version: v2" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>" \
-d '{
"data": {
"url": "https://www.example.com/webhooks",
"events": [
"order.created",
"order.airline_initiated_change_detected"
]
}
}'

Response

{
"data": {
"secret": "QKfUULLQh+8SegYmIsF6kA==",
"url": "https://www.example.com:4000/webhooks",
"updated_at": "2020-04-11T15:48:11.642Z",
"live_mode": true,
"id": "end_0000A3tQSmKyqOrcySrGbo",
"events": [
"order.created",
"order.airline_initiated_change_detected"
],
"created_at": "2020-04-11T15:48:11.642Z",
"active": true
}
}