{"id":13878468,"url":"https://github.com/duffelhq/duffel-api-ruby","last_synced_at":"2025-07-16T14:32:23.211Z","repository":{"id":38361326,"uuid":"435958728","full_name":"duffelhq/duffel-api-ruby","owner":"duffelhq","description":"Ruby client library for the Duffel API","archived":false,"fork":false,"pushed_at":"2023-08-30T10:32:11.000Z","size":407,"stargazers_count":6,"open_issues_count":3,"forks_count":5,"subscribers_count":7,"default_branch":"main","last_synced_at":"2024-04-25T18:21:16.926Z","etag":null,"topics":["api-client","client-library","duffel","duffel-api","flights-api","ruby"],"latest_commit_sha":null,"homepage":"https://duffel.com/docs","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/duffelhq.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-07T16:50:08.000Z","updated_at":"2024-08-06T08:47:12.215Z","dependencies_parsed_at":"2024-08-06T08:47:03.569Z","dependency_job_id":"4fae37e2-3ef1-4067-9176-28592f060a75","html_url":"https://github.com/duffelhq/duffel-api-ruby","commit_stats":{"total_commits":152,"total_committers":10,"mean_commits":15.2,"dds":0.5460526315789473,"last_synced_commit":"d04e8cd0997184a98a092c330750edbdf7812c16"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duffelhq%2Fduffel-api-ruby","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duffelhq%2Fduffel-api-ruby/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duffelhq%2Fduffel-api-ruby/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duffelhq%2Fduffel-api-ruby/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/duffelhq","download_url":"https://codeload.github.com/duffelhq/duffel-api-ruby/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226138849,"owners_count":17579496,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-client","client-library","duffel","duffel-api","flights-api","ruby"],"created_at":"2024-08-06T08:01:50.839Z","updated_at":"2024-11-24T07:31:06.183Z","avatar_url":"https://github.com/duffelhq.png","language":"Ruby","readme":"\u003e [!WARNING] \n\u003e This client library is not currently being supported by Duffel due to a lack of adoption.\n\u003e \n\u003e You're welcome to fork the repositories and continue maintaining them for your own use.\n\u003e\n\u003e If, in the future, there's sufficient demand for a particular client library, we'll reconsider our decision to officially support it.\n\n---\n\n# Duffel API Ruby client library\n\n[![RubyDoc.info documentation](http://img.shields.io/badge/yard-docs-blue.svg)](https://rubydoc.info/github/duffelhq/duffel-api-ruby)\n\nA Ruby client library for the [Duffel API](https://duffel.com/docs/api).\n\n## Contents\n\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Usage](#usage)\n\n## Requirements\n\n* Ruby 2.6 or later\n* A Duffel API access token (get started [here](https://duffel.com/docs/guides/quick-start) ✨)\n\n## Installation\n\nIn most cases, you'll want to add `duffel_api` to your project as a dependency by listing it in your `Gemfile`, and then running `bundle`:\n\n```ruby\ngem \"duffel_api\", \"~\u003e 0.4.0\"\n```\n\nYou can install `duffel_api` outside of the context of a project by running `gem install duffel_api` - for example if you want to play with the client library in `irb`.\n\n## Usage\n\nYou can see a complete end-to-end example of searching and booking using the client library in [`example/search_and_book.rb`](https://github.com/duffelhq/duffel-api-ruby/blob/main/examples/search_and_book.rb).\n\n### Initialising the client\n\nAll of the library's functionality is accessed from a `DuffelAPI::Client` instance.\n\nTo initialise a `DuffelAPI::Client`, all you'll need is your API access token:\n\n```ruby\nrequire \"duffel_api\"\n\nclient = DuffelAPI::Client.new(access_token: \"duffel_test_000000000\")\n```\n\n### Resources in the Duffel API\n\nIn this readme, we'll use the term \"resources\" to refer to the different Duffel concepts that you can *act on* in the API - for example airports, offers, orders and payment intents.\n\nWe'll refer to instances of each of these resources - an airport, an offer, a payment intent - as \"records\".\n\nIn the [Duffel API reference](https://duffel.com/docs/api/), the resources are listed in the sidebar. For each resource, you'll find:\n\n* a schema, which describes the data attributes we expose for each record from this resource\n* a list of actions you can perform related to that resource (e.g. for [Orders](https://duffel.com/docs/api/orders), you can \"Get a single order\", \"Update a single order\", \"List orders\" and \"Create an order\")\n\nThe Ruby client library is structured around these resources. Each resource has its own \"service\" which you use to perform actions. These services are accessible from your `Client` instance:\n\n```ruby\nclient.orders\nclient.offers\nclient.payment_intents\n```\n\n__To see what actions are available for each resource, check out the definitions for the service classes [here](https://github.com/duffelhq/duffel-api-ruby/tree/main/lib/duffel_api/services).__\n\n### Creating a record\n\nMost resources allow you to create a record. In fact, the most important flows in the Duffel API start with creating a record. You'll do this with the `#create` method exposed on a service.\n\nFor example, you'll search for flights by creating an offer request:\n\n```ruby\noffer_request = client.offer_requests.create(params: {\n  cabin_class: \"economy\",\n  passengers: [{\n    age: 28\n  }],\n  slices: [{\n    origin: \"LHR\",\n    destination: \"NYC\",\n    departure_date: \"2022-12-31\"\n  }],\n  # This attribute is sent as a query parameter rather than in the body like the others.\n  # Worry not! The library handles this complexity for you.\n  return_offers: false\n})\n\nputs \"You've created an offer request, #{offer_request.id}.\"\n```\n\nThe `#create` method returns the created record.\n\n### Listing records\n\nMany resources in the Duffel API (e.g. airports, orders and offers) allow you to list their records.\n\nFor example, you can get a list of all the airports that Duffel knows about - that is, a list of airport records.\n\nFor performance reasons, we [paginate](https://duffel.com/docs/api/overview/pagination) records in the API when listing. You can only see up to 200 at a time. You'll need to page through, like moving through pages of a book.\n\nThis is quite fiddly, so the client library does it for you in the `#all` method exposed by relevant services. All you have to do is something like this:\n\n```ruby\nclient.offer_requests.all.each do |offer_request|\n  puts \"Loaded offer request #{order_request.id}\"\nend\n```\n\nSometimes, you'll want to specify filters or sort orders when listing,like this:\n\n```ruby\n# The filters you can use for a given resource are documented in the API Reference\nclient.offers.\n  all(params: { offer_request_id: \"ofr_123\", sort: \"total_amount\" }).\n  each do |order|\n    puts \"Loaded order #{order.id}\"\n  end\n```\n\nA call to `#all` returns a Ruby [`Enumerator`](https://ruby-doc.org/core-2.6/Enumerator.html), which behaves a lot like an array - you can get the number of records with `#length`, loop through it with `#each`, etc.\n\nIf you prefer, you can also page through records manually using a service's `#list` method (e.g. `client.orders.list`) which returns a `DuffelAPI::ListResponse`.\n\nThe records in the page are returned by `#records` (`client.orders.list.records`) and the cursor for the next page (if there is one) can be found with `#after` (`client.orders.list.after`)\n\n#### An exception: seat maps\n\nWatch out! There is one kind of list in the Duffel API which isn't paginated: seat maps.\n\nWhen you call `client.seat_maps.list(params: { offer_id: \"off_123\" })`, all of the seat maps will be returned at once in a single `ListResponse`.\n\n### Fetching single records\n\nMany resources in the Duffel API allow you fetch a single record (e.g. *an* airport, *a* payment intent) if you know its ID.\n\nYou do that using the `#get` method on a resource like this:\n\n```ruby\norder = client.orders.get(\"ord_123\")\nputs \"Your booking reference is #{order.booking_reference}.\"\n```\n\nThe `#get` method returns the record.\n\n### Updating a record\n\nSome records in the Duffel API allow you to update them after they've been created, if you know their ID.\n\nThat works like this using the `#update` method on a resource:\n\n```ruby\nclient.webhooks.update(\"sev_0000AEdmUJKCvFK45qMFBg\", params: {\n  active: false\n})\n```\n\nThe `#update` method returns the updated record.\n\n### Performing an action on a record\n\nSome resources allow you to perform special actions on their records - for example confirming an order cancellation or pinging a webhook.\n\nThe methods you'll use to do this aren't named consistently, because each resource has different actions. For example, you'll call `#confirm` to confirm an order cancellation but `#ping` to ping a webhook.\n\nIt'll look a bit like this:\n\n```ruby\nclient.order_cancellations.confirm(\"ore_0000AEUvjGoJlav2j6FDlZ\")\n```\n\nSometimes, you'll need to pass extra data when performing the action. That works like this:\n\n```ruby\nclient.order_changes.confirm(\"oce_0000AEdlOBVlABkDhgsUqW\", params: {\n  payment: {\n    type: \"balance\",\n    currency: \"GBP\",\n    amount: \"125.00\",\n  }\n})\n```\n\nIn general, these action methods return the record you've acted on.\n\n#### An exception: pinging a webhook\n\nWatch out! There is one action in the API which doesn't return the record you've acted on.\n\nWhen you ping a webhook with `client.webhooks.ping(\"sev_0000AEdmUJKCvFK45qMFBg\")`, it'll return a `DuffelAPI::Services::WebhooksService::PingResult` if successful, or otherwise it'll raise an error.\n\n### Handling errors\n\nWhen the Duffel API returns an error, the library will raise an exception.\n\nWe have an exception class for each of the possible `type`s of error which the API can return, documented [here](https://duffel.com/docs/api/overview/errors) in the API reference. For example, if the API returns an error with `type` `invalid_state_error`, the library will raise a `DuffelAPI::Errors::InvalidStateError` exception.\n\nYou can find all of those error classes [here](https://github.com/duffelhq/duffel-api-ruby/tree/main/lib/duffel_api/errors).\n\nYou can rescue all of these errors and get important information with them using instances methods: `#message`, `#title`, `#code`, `#request_id`, etc.\n\nIf the client library is unable to connect to Duffel, an appropriate exception will be raised, for example:\n\n* `Faraday::TimeoutError` in case of a timeout\n* `Faraday::ConnectionFailed` in case of a connection issue (e.g. problems with DNS resolution)\n* `DuffelAPI::Errors::Error` for `5XX` errors returned from by Duffel's infrastructure, but not by the API itself (e.g. a load balancer)\n\n### Accessing the raw API response\n\nSometimes, you might want to get lower-level details about the response you received from the Duffel API - for example the raw body or headers.\n\nIf an error has been raised, you can call `#api_response` on the exception, which returns a `DuffelAPI::APIResponse`. If you're looking at a `ListResponse` or any resource, you can call `#api_response` on that.\n\nFrom the `APIResponse`, you can call `#headers`, `#status_code`, `#raw_body`, `#parsed_body`, `#meta` or `#request_id` to get key information from the response.\n\n### Verifying webhooks\n\nYou can set up [webhooks](https://duffel.com/docs/guides/receiving-webhooks) with Duffel to receive notifications about events that happen in your Duffel account - for example, when an airline has a schedule change affecting one of your orders.\n\nThese webhook events are signed with a shared secret. This allows you to be sure that any webhook events are genuinely sent from Duffel when you receive them.\n\nWhen you create a webhook, you'll set a secret. With that secret in mind, you can verify that a webhook is genuine like this:\n\n```ruby\n# In Rails, you'd get this with `request.raw_post`.\nrequest_body = '{\"created_at\":\"2022-01-08T18:44:56.129339Z\",\"data\":{\"changes\":{},\"object\":{}},\"id\":\"eve_0000AFEsrBKZAcKgGtZCnQ\",\"live_mode\":false,\"object\":\"order\",\"type\":\"order.updated\"}'\n# In Rails, you'd get this with `request.headers['X-Duffel-Signature']`.\nrequest_signature = \"t=1641667496,v1=691f25ffb1f206c0fda5bb7b1a9d60fafe42c5f42819d44a06a7cfe09486f102\"\n\n# Note that this code doesn't require your access token - `DuffelAPI::WebhookEvent`\n# doesn't expect you to have a `Client` initialised\nif DuffelAPI::WebhookEvent.genuine?(\n  request_body: request_body,\n  request_signature: request_signature,\n  webhook_secret: \"a_secret\"\n)\n  puts \"This is a real webhook from Duffel 🌟\"\nelse\n  puts \"This is a fake webhook! ☠️\"\nend\n```\n\n## Learn more\n\nYou can find complete documentation on this library's classes and methods in the in-code\ndocumentation on [RubyDoc.info](https://rubydoc.info/github/duffelhq/duffel-api-ruby).\n","funding_links":[],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fduffelhq%2Fduffel-api-ruby","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fduffelhq%2Fduffel-api-ruby","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fduffelhq%2Fduffel-api-ruby/lists"}