{"id":24764481,"url":"https://github.com/seamapi/ruby","last_synced_at":"2026-04-24T08:01:09.981Z","repository":{"id":234322626,"uuid":"788653986","full_name":"seamapi/ruby","owner":"seamapi","description":"SDK for the Seam API written in Ruby.","archived":false,"fork":false,"pushed_at":"2026-04-22T06:17:28.000Z","size":663,"stargazers_count":2,"open_issues_count":6,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-04-22T07:43:48.892Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/seam","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/seamapi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-04-18T20:37:43.000Z","updated_at":"2026-04-22T06:17:32.000Z","dependencies_parsed_at":"2026-04-16T08:00:47.736Z","dependency_job_id":null,"html_url":"https://github.com/seamapi/ruby","commit_stats":{"total_commits":77,"total_committers":9,"mean_commits":8.555555555555555,"dds":0.6753246753246753,"last_synced_commit":"24cb6e39c26f046ee4766a15c222c6668b076760"},"previous_names":["seamapi/ruby-next","seamapi/ruby"],"tags_count":126,"template":false,"template_full_name":null,"purl":"pkg:github/seamapi/ruby","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seamapi%2Fruby","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seamapi%2Fruby/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seamapi%2Fruby/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seamapi%2Fruby/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/seamapi","download_url":"https://codeload.github.com/seamapi/ruby/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seamapi%2Fruby/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32214420,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-24T03:15:14.334Z","status":"ssl_error","status_checked_at":"2026-04-24T03:15:11.608Z","response_time":64,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2025-01-28T22:31:36.475Z","updated_at":"2026-04-24T08:01:09.959Z","avatar_url":"https://github.com/seamapi.png","language":"Ruby","readme":"# Seam Ruby SDK\n\n[![RubyGems.org](https://img.shields.io/gem/v/seam)](https://rubygems.org/gems/seam)\n[![GitHub Actions](https://github.com/seamapi/ruby-next/actions/workflows/check.yml/badge.svg)](https://github.com/seamapi/ruby-next/actions/workflows/check.yml)\n\nSDK for the Seam API written in Ruby.\n\n## Description\n\n[Seam](https://seam.co) makes it easy to integrate IoT devices with your applications.\nThis is an official SDK for the Seam API.\nPlease refer to the official [Seam Docs](https://docs.seam.co/latest/) to get started.\n\nParts of this SDK are generated from always up-to-date type information\nprovided by [@seamapi/types](https://github.com/seamapi/types/).\nThis ensures all API methods, request shapes, and response shapes are\naccurate and fully typed.\n\n\u003c!-- toc --\u003e\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Examples](#examples)\n    - [List devices](#list-devices)\n    - [Unlock a door](#unlock-a-door)\n  - [Authentication Method](#authentication-method)\n    - [API Key](#api-key)\n    - [Personal Access Token](#personal-access-token)\n  - [Action Attempts](#action-attempts)\n  - [Pagination](#pagination)\n    - [Manually fetch pages with the next_page_cursor](#manually-fetch-pages-with-the-next_page_cursor)\n    - [Resume pagination](#resume-pagination)\n    - [Iterate over all resources](#iterate-over-all-resources)\n    - [Return all resources across all pages as a list](#return-all-resources-across-all-pages-as-a-list)\n  - [Interacting with Multiple Workspaces](#interacting-with-multiple-workspaces)\n  - [Webhooks](#webhooks)\n  - [Advanced Usage](#advanced-usage)\n    - [Additional Options](#additional-options)\n    - [Setting the endpoint](#setting-the-endpoint)\n    - [Configuring the Faraday Client](#configuring-the-faraday-client)\n    - [Using the Faraday Client](#using-the-faraday-client)\n    - [Overriding the Client](#overriding-the-client)\n- [Development and Testing](#development-and-testing)\n  - [Quickstart](#quickstart)\n  - [Source code](#source-code)\n  - [Requirements](#requirements)\n  - [Publishing](#publishing)\n    - [Automatic](#automatic)\n    - [Manual](#manual)\n- [GitHub Actions](#github-actions)\n  - [Secrets for Optional GitHub Actions](#secrets-for-optional-github-actions)\n- [Contributing](#contributing)\n- [License](#license)\n- [Warranty](#warranty)\n\n\u003c!-- tocstop --\u003e\n\n## Installation\n\nAdd this as a dependency to your project using [Bundler] with:\n\n```\n$ bundle add seam\n```\n\n[Bundler]: https://bundler.io/\n\n## Usage\n\n### Examples\n\n\u003e [!NOTE]\n\u003e These examples assume `SEAM_API_KEY` is set in your environment.\n\n#### List devices\n\n```ruby\nrequire \"seam\"\n\nseam = Seam.new\ndevices = seam.devices.list\n```\n\n#### Unlock a door\n\n```ruby\nrequire \"seam\"\n\nseam = Seam.new\nlock = seam.locks.get(name: \"Front Door\")\nseam.locks.unlock_door(device_id: lock.device_id)\n```\n\n### Authentication Method\n\nThe SDK supports API key and personal access token authentication mechanisms.\nAuthentication may be configured by passing the corresponding options directly to the `Seam` constructor, or with the more ergonomic static factory methods.\n\n#### API Key\n\nAn API key is scoped to a single workspace and should only be used on the server.\nObtain one from the Seam Console.\n\n```ruby\n# Set the `SEAM_API_KEY` environment variable\nseam = Seam.new\n\n# Pass as a keyword argument to the constructor\nseam = Seam.new(api_key: \"your-api-key\")\n\n# Use the factory method\nseam = Seam.from_api_key(\"your-api-key\")\n```\n\n#### Personal Access Token\n\nA Personal Access Token is scoped to a Seam Console user.\nObtain one from the Seam Console.\nA workspace ID must be provided when using this method and all requests will be scoped to that workspace.\n\n```ruby\n# Pass as an option to the constructor\nseam = Seam.new(\n  personal_access_token: \"your-personal-access-token\",\n  workspace_id: \"your-workspace-id\"\n)\n\n# Use the factory method\nseam = Seam.from_personal_access_token(\n  \"your-personal-access-token\",\n  \"your-workspace-id\"\n)\n```\n\n### Action Attempts\n\nSome asynchronous operations, e.g., unlocking a door, return an\n[action attempt](https://docs.seam.co/latest/core-concepts/action-attempts).\nSeam tracks the progress of the requested operation and updates the action attempt\nwhen it succeeds or fails.\n\nTo make working with action attempts more convenient for applications,\nthis library provides the `wait_for_action_attempt` option and enables it by default.\n\nWhen the `wait_for_action_attempt` option is enabled, the SDK:\n\n- Polls the action attempt up to the `timeout`\n  at the `polling_interval` (both in seconds).\n- Resolves with a fresh copy of the successful action attempt.\n- Raises a `Seam::ActionAttemptFailedError` if the action attempt is unsuccessful.\n- Raises a `Seam::ActionAttemptTimeoutError` if the action attempt is still pending when the `timeout` is reached.\n- Both errors expose an `action_attempt` property.\n\nIf you already have an action attempt ID\nand want to wait for it to resolve, simply use:\n\n```ruby\nseam.action_attempts.get(action_attempt_id: action_attempt_id)\n```\n\nOr, to get the current state of an action attempt by ID without waiting:\n\n```ruby\nseam.action_attempts.get(\n  action_attempt_id: action_attempt_id,\n  wait_for_action_attempt: false\n)\n```\n\nTo disable this behavior, set the default option for the client:\n\n```ruby\nseam = Seam.new(\n  api_key: \"your-api-key\",\n  wait_for_action_attempt: false\n)\n\nseam.locks.unlock_door(device_id: device_id)\n```\n\nor the behavior may be configured per-request:\n\n```ruby\nseam.locks.unlock_door(\n  device_id: device_id,\n  wait_for_action_attempt: false\n)\n```\n\nThe `polling_interval` and `timeout` may be configured for the client or per-request.\nFor example:\n\n```ruby\nrequire \"seam\"\n\nseam = Seam.new(\"your-api-key\")\n\nlocks = seam.locks.list\n\nif locks.empty?\n  raise \"No locks in this workspace\"\nend\n\nlock = locks.first\n\nbegin\n  seam.locks.unlock_door(\n    device_id: lock.device_id,\n    wait_for_action_attempt: {\n      timeout: 5.0,\n      polling_interval: 1.0\n    }\n  )\n\n  puts \"Door unlocked\"\nrescue Seam::ActionAttemptFailedError\n  puts \"Could not unlock the door\"\nrescue Seam::ActionAttemptTimeoutError\n  puts \"Door took too long to unlock\"\nend\n```\n\n### Pagination\n\nSome Seam API endpoints that return lists of resources support pagination.\nUse the `Seam::Paginator` class to fetch and process resources across multiple pages.\n\n#### Manually fetch pages with the next_page_cursor\n\n```ruby\nrequire \"seam\"\n\nseam = Seam.new\n\npaginator = seam.create_paginator(seam.devices.method(:list), {limit: 20})\n\ndevices, pagination = paginator.first_page\n\nif pagination.has_next_page?\n  more_devices, _ = paginator.next_page(pagination.next_page_cursor)\nend\n```\n\n#### Resume pagination\n\nGet the first page on initial load and store the state (e.g., in memory or a file):\n\n```ruby\nrequire \"seam\"\nrequire \"json\"\n\nseam = Seam.new\n\nparams = {limit: 20}\npaginator = seam.create_paginator(seam.devices.method(:list), params)\n\ndevices, pagination = paginator.first_page\n\n# Example: Store state for later use (e.g., in a file or database)\npagination_state = {\n  \"params\" =\u003e params,\n  \"next_page_cursor\" =\u003e pagination.next_page_cursor,\n  \"has_next_page\" =\u003e pagination.has_next_page?\n}\nFile.write(\"/tmp/seam_devices.json\", JSON.dump(pagination_state))\n```\n\nGet the next page at a later time using the stored state:\n\n```ruby\nrequire \"seam\"\nrequire \"json\"\n\nseam = Seam.new\n\n# Example: Load state from where it was stored\npagination_state_json = File.read(\"/tmp/seam_devices.json\")\npagination_state = JSON.parse(pagination_state_json)\n\nif pagination_state[\"has_next_page\"]\n  paginator = seam.create_paginator(\n    seam.devices.method(:list), pagination_state[\"params\"]\n  )\n  more_devices, _ = paginator.next_page(\n    pagination_state[\"next_page_cursor\"]\n  )\nend\n```\n\n#### Iterate over all resources\n\n```ruby\nrequire \"seam\"\n\nseam = Seam.new\n\npaginator = seam.create_paginator(seam.devices.method(:list), {limit: 20})\n\npaginator.flatten.each do |account|\n  puts account.account_type_display_name\nend\n```\n\n#### Return all resources across all pages as a list\n\n```ruby\nrequire \"seam\"\n\nseam = Seam.new\n\npaginator = seam.create_paginator(seam.devices.method(:list), {limit: 20})\n\nall_devices = paginator.flatten_to_list\n```\n\n### Interacting with Multiple Workspaces\n\nSome Seam API endpoints interact with multiple workspaces. The `Seam::Http::SeamMultiWorkspace` client is not bound to a specific workspace and may use those endpoints with a personal access token authentication method.\n\nA Personal Access Token is scoped to a Seam Console user. Obtain one from the Seam Console.\n\n```ruby\n# Pass as an option to the constructor\nseam = Seam::Http::SeamMultiWorkspace.new(personal_access_token: \"your-personal-access-token\")\n\n# Use the factory method\nseam = Seam::Http::SeamMultiWorkspace.from_personal_access_token(\"your-personal-access-token\")\n\n# List workspaces authorized for this Personal Access Token\nworkspaces = seam.workspaces.list\n```\n\n### Webhooks\n\nThe Seam API implements webhooks using [Svix](https://www.svix.com).This SDK exports a thin wrapper `Seam::Webhook` around the svix package.\nUse it to parse and validate Seam webhook events.\n\n\u003e [!TIP]\n\u003e This example is for [Sinatra](https://sinatrarb.com/), see the [Svix docs for more examples in specific frameworks](https://docs.svix.com/receiving/verifying-payloads/how).\n\n```ruby\nrequire \"sinatra\"\nrequire \"seam\"\n\nwebhook = Seam::Webhook.new(ENV[\"SEAM_WEBHOOK_SECRET\"])\n\npost \"/webhook\" do\n  begin\n    headers = {\n      \"svix-id\" =\u003e request.env[\"HTTP_SVIX_ID\"],\n      \"svix-signature\" =\u003e request.env[\"HTTP_SVIX_SIGNATURE\"],\n      \"svix-timestamp\" =\u003e request.env[\"HTTP_SVIX_TIMESTAMP\"]\n    }\n    data = webhook.verify(request.body.read, headers)\n  rescue Seam::WebhookVerificationError\n    halt 400, \"Bad Request\"\n  end\n\n  begin\n    store_event(data)\n  rescue\n    halt 500, \"Internal Server Error\"\n  end\n\n  204\nend\n\ndef store_event(data)\n  puts data\nend\n```\n\n### Advanced Usage\n\n#### Additional Options\n\nIn addition to the various authentication options,\nthe constructor takes some advanced options that affect behavior.\n\n```ruby\nseam = Seam.new(\n  api_key: \"your-api-key\",\n  endpoint: \"https://example.com\",\n  faraday_options: {},\n  faraday_retry_options: {}\n)\n```\n\nWhen using the static factory methods,\nthese options may be passed in as keyword arguments.\n\n```ruby\nseam = Seam.from_api_key(\"some-api-key\",\n  endpoint: \"https://example.com\",\n  faraday_options: {},\n  faraday_retry_options: {})\n```\n\n#### Setting the endpoint\n\nSome contexts may need to override the API endpoint,\ne.g., testing or proxy setups. This option corresponds to the [Faraday](https://lostisland.github.io/faraday/#/) `url` setting.\n\nEither pass the `endpoint` option, or set the `SEAM_ENDPOINT` environment variable.\n\n#### Configuring the Faraday Client\n\nThe Faraday client and retry behavior may be configured with custom initiation options\nvia [`faraday_option`][faraday_option] and [`faraday_retry_option`][faraday_retry_option].\n\n[faraday_option]: https://lostisland.github.io/faraday/#/customization/connection-options?id=connection-options\n[faraday_retry_option]: https://github.com/lostisland/faraday-retry\n\n#### Using the Faraday Client\n\nThe Faraday client is exposed and may be used or configured directly:\n\n```ruby\nrequire \"seam\"\nrequire \"faraday\"\n\nclass MyMiddleware \u003c Faraday::Middleware\n  def on_complete(env)\n    puts env.response.inspect\n  end\nend\n\nseam = Seam.new\n\nseam.client.builder.use MyMiddleware\n\ndevices = seam.client.get(\"/devices/list\").body[\"devices\"]\n```\n\n#### Overriding the Client\n\nA Faraday compatible client may be provided to create a `Seam` instance.\nThis API is used internally and is not directly supported.\n\n## Development and Testing\n\n### Quickstart\n\n```\n$ git clone https://github.com/seamapi/ruby-next.git\n$ cd ruby-next\n$ bundle install\n```\n\nRun the command below\n\n```\n$ bundle exec rake\n```\n\nOpen an interactive ruby console with\n\n```\n$ bundle exec rake\n```\n\nPrimary development tasks are defined as [rake] tasks in the `Rakefile`\nand available via `rake`.\nView them with\n\n```\n$ bundle exec rake -T\n```\n\n[rake]: https://ruby.github.io/rake/\n\n### Source code\n\nThe [source code] is hosted on GitHub.\nClone the project with\n\n```\n$ git clone git@github.com:seamapi/ruby-next.git\n```\n\n[source code]: https://github.com/seamapi/ruby-next\n\n### Requirements\n\nYou will need [Ruby] with [Bundler] and [Node.js] with [npm].\n\nBe sure that all commands run under the correct Ruby version, e.g.,\nif using [rbenv], install the correct version with\n\n```\n$ rbenv install\n$ npm install\n```\n\nInstall the development dependencies with\n\n```\n$ bundle install\n```\n\n[bundler]: https://bundler.io/\n[Node.js]: https://nodejs.org/\n[npm]: https://www.npmjs.com/\n[ruby]: https://www.ruby-lang.org/\n[rbenv]: https://github.com/rbenv/rbenv\n\n### Publishing\n\nNew versions are created with [gem release].\n\n#### Automatic\n\nNew versions are released automatically with [semantic-release]\nas long as commits follow the [Angular Commit Message Conventions].\n\n[Angular Commit Message Conventions]: https://semantic-release.gitbook.io/semantic-release/#commit-message-format\n[semantic-release]: https://semantic-release.gitbook.io/\n\n#### Manual\n\nPublish a new version by triggering a [version workflow_dispatch on GitHub Actions].\nThe `version` input will be passed to the `--version` option of `gem bump`.\n\nThis may be done on the web or using the [GitHub CLI] with\n\n```\n$ gh workflow run version.yml --raw-field version=\u003cversion\u003e\n```\n\n[gem release]: https://github.com/svenfuchs/gem-release\n[GitHub CLI]: https://cli.github.com/\n[version workflow_dispatch on GitHub Actions]: https://github.com/seamapi/ruby-next/actions?query=workflow%3Aversion\n\n## GitHub Actions\n\n_GitHub Actions should already be configured: this section is for reference only._\n\nThe following repository secrets must be set on [GitHub Actions]:\n\n- `RUBYGEMS_API_KEY`: RubyGems.org token for publishing gems.\n\nThese must be set manually.\n\n### Secrets for Optional GitHub Actions\n\nThe version, format, generate, and semantic-release GitHub actions\nrequire a user with write access to the repository.\nSet these additional secrets to enable the action:\n\n- `GH_TOKEN`: A personal access token for the user.\n- `GIT_USER_NAME`: The GitHub user's real name.\n- `GIT_USER_EMAIL`: The GitHub user's email.\n- `GPG_PRIVATE_KEY`: The GitHub user's [GPG private key].\n- `GPG_PASSPHRASE`: The GitHub user's GPG passphrase.\n\n[github actions]: https://github.com/features/actions\n[gpg private key]: https://github.com/marketplace/actions/import-gpg#prerequisites\n\n## Contributing\n\nPlease submit and comment on bug reports and feature requests.\n\nTo submit a patch:\n\n1. Fork it (https://github.com/seamapi/ruby-next/fork).\n2. Create your feature branch (`git checkout -b my-new-feature`).\n3. Make changes.\n4. Commit your changes (`git commit -am 'Add some feature'`).\n5. Push to the branch (`git push origin my-new-feature`).\n6. Create a new Pull Request.\n\n## License\n\nThis Ruby gem is licensed under the MIT license.\n\n## Warranty\n\nThis software is provided by the copyright holders and contributors \"as is\" and\nany express or implied warranties, including, but not limited to, the implied\nwarranties of merchantability and fitness for a particular purpose are\ndisclaimed. In no event shall the copyright holder or contributors be liable for\nany direct, indirect, incidental, special, exemplary, or consequential damages\n(including, but not limited to, procurement of substitute goods or services;\nloss of use, data, or profits; or business interruption) however caused and on\nany theory of liability, whether in contract, strict liability, or tort\n(including negligence or otherwise) arising in any way out of the use of this\nsoftware, even if advised of the possibility of such damage.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseamapi%2Fruby","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fseamapi%2Fruby","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseamapi%2Fruby/lists"}