{"id":24764478,"url":"https://github.com/seamapi/python","last_synced_at":"2026-03-06T11:16:08.141Z","repository":{"id":231162240,"uuid":"781045227","full_name":"seamapi/python","owner":"seamapi","description":"SDK for the Seam API written in Python.","archived":false,"fork":false,"pushed_at":"2026-01-16T09:56:09.000Z","size":958,"stargazers_count":17,"open_issues_count":9,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-01-16T20:11:05.983Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://pypi.org/project/seam/","language":"Python","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.rst","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-02T16:41:59.000Z","updated_at":"2026-01-16T09:56:12.000Z","dependencies_parsed_at":"2026-01-16T08:07:39.933Z","dependency_job_id":null,"html_url":"https://github.com/seamapi/python","commit_stats":null,"previous_names":["seamapi/python-next","seamapi/python"],"tags_count":191,"template":false,"template_full_name":null,"purl":"pkg:github/seamapi/python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seamapi%2Fpython","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seamapi%2Fpython/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seamapi%2Fpython/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seamapi%2Fpython/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/seamapi","download_url":"https://codeload.github.com/seamapi/python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seamapi%2Fpython/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28602175,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T10:46:13.255Z","status":"ssl_error","status_checked_at":"2026-01-20T10:42:51.865Z","response_time":117,"last_error":"SSL_read: 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:34.821Z","updated_at":"2026-01-20T11:08:51.582Z","avatar_url":"https://github.com/seamapi.png","language":"Python","readme":"Seam Python SDK\n===============\n\n|PyPI| |GitHub Actions|\n\n.. |PyPI| image:: https://img.shields.io/pypi/v/seam.svg\n   :target: https://pypi.python.org/pypi/seam\n   :alt: PyPI\n.. |GitHub Actions| image:: https://github.com/seamapi/python/actions/workflows/check.yml/badge.svg\n   :target: https://github.com/seamapi/python/actions/workflows/check.yml\n   :alt: GitHub Actions\n\nSDK for the Seam API written in Python.\n\nDescription\n-----------\n\n`Seam \u003cseam_home_\u003e`_ 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 \u003chttps://docs.seam.co/latest/\u003e`_ to get started.\n\nParts of this SDK are generated from always up-to-date type information\nprovided by `@seamapi/types \u003chttps://github.com/seamapi/types/\u003e`_ node package.\nThis ensures all API methods, request shapes, and response shapes are\naccurate and fully typed.\n\n.. _seam_home: https://www.seam.co\n\nContents\n--------\n\n* `Installation \u003cInstallation_\u003e`_\n\n* `Usage \u003cUsage_\u003e`_\n\n  * `Examples \u003cExamples_\u003e`_\n\n    * `List devices \u003cList devices_\u003e`_\n\n    * `Unlock a door \u003cUnlock a door_\u003e`_\n\n  * `Authentication Method \u003cAuthentication Method_\u003e`_\n\n    * `API Key \u003cAPI Key_\u003e`_\n\n    * `Personal Access Token \u003cPersonal Access Token_\u003e`_\n\n  * `Action Attempts \u003cAction Attempts_\u003e`_\n\n  * `Pagination \u003cPagination_\u003e`_\n\n    * `Manually fetch pages with the nextPageCursor \u003cManually fetch pages with the nextPageCursor_\u003e`_\n\n    * `Resume pagination \u003cResume pagination_\u003e`_\n\n    * `Iterate over all resources \u003cIterate over all resources_\u003e`_\n\n    * `Return all resources across all pages as a list \u003cReturn all resources across all pages as a list_\u003e`_\n\n  * `Interacting with Multiple Workspaces \u003cInteracting with Multiple Workspaces_\u003e`_\n\n  * `Webhooks \u003cWebhooks_\u003e`_\n\n  * `Advanced Usage \u003cAdvanced Usage_\u003e`_\n\n    * `Setting the endpoint \u003cSetting the endpoint_\u003e`_\n\n* `Development and Testing \u003cDevelopment and Testing_\u003e`_\n\n  * `Quickstart \u003cQuickstart_\u003e`_\n\n  * `Source Code \u003cSource Code_\u003e`_\n\n  * `Requirements \u003cRequirements_\u003e`_\n\n  * `Tests \u003cTests_\u003e`_\n\n  * `Publishing \u003cPublishing_\u003e`_\n\n    * `Automatic \u003cAutomatic_\u003e`_\n\n    * `Manual \u003cManual_\u003e`_\n\n* `GitHub Actions \u003cGitHub Actions_\u003e`_\n\n  * `Secrets for Optional GitHub Actions \u003cSecrets for Optional GitHub Actions_\u003e`_\n\n* `Contributing \u003cContributing_\u003e`_\n\n* `License \u003cLicense_\u003e`_\n\n* `Warranty \u003cWarranty_\u003e`_\n\nInstallation\n------------\n\nThis package is registered on the `Python Package Index (PyPI)`_\nas seam_.\n\nInstall it with::\n\n    $ pip install seam\n\n.. _seam: https://pypi.python.org/pypi/seam\n.. _Python Package Index (PyPI): https://pypi.python.org/\n\nUsage\n-----\n\nExamples\n~~~~~~~~\n\n**Note:** *These examples assume `SEAM_API_KEY` is set in your environment.*\n\nList devices\n^^^^^^^^^^^^\n\n.. code-block:: python\n\n  from seam import Seam\n\n  seam = Seam()\n  devices = seam.devices.list()\n\nUnlock a door\n^^^^^^^^^^^^^\n\n.. code-block:: python\n\n  from seam import Seam\n\n  seam = Seam()\n  lock = seam.locks.get(name=\"Front Door\")\n  seam.locks.unlock_door(device_id=lock.device_id)\n\nAuthentication Method\n~~~~~~~~~~~~~~~~~~~~~\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\nAPI Key\n^^^^^^^\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.. code-block:: python\n\n  # Set the `SEAM_API_KEY` environment variable\n  seam = Seam()\n\n  # Pass as the first argument to the constructor\n  seam = Seam(\"your-api-key\")\n\n  # Pass as a keyword argument to the constructor\n  seam = Seam(api_key=\"your-api-key\")\n\n  # Use the factory method\n  seam = Seam.from_api_key(\"your-api-key\")\n\nPersonal Access Token\n^^^^^^^^^^^^^^^^^^^^^\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.. code-block:: python\n\n  # Pass as an option to the constructor\n  seam = Seam(\n      personal_access_token=\"your-personal-access-token\",\n      workspace_id=\"your-workspace-id\",\n  )\n\n  # Use the factory method\n  seam = Seam.from_personal_access_token(\n      \"your-personal-access-token\",\n      \"your-workspace-id\",\n  )\n\nAction Attempts\n~~~~~~~~~~~~~~~\n\nSome asynchronous operations, e.g., unlocking a door, return an\n`action attempt \u003chttps://docs.seam.co/latest/core-concepts/action-attempts\u003e`_.\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 ``SeamActionAttemptFailedError`` if the action attempt is unsuccessful.\n- Raises a ``SeamActionAttemptTimeoutError`` 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.. code-block:: python\n\n  seam.action_attempts.get(action_attempt_id=action_attempt_id)\n\nOr, to get the current state of an action attempt by ID without waiting,\n\n.. code-block:: python\n\n  seam.action_attempts.get(\n      action_attempt_id=action_attempt_id,\n      wait_for_action_attempt=False,\n  )\n\nTo disable this behavior, set the default option for the client:\n\n.. code-block:: python\n\n  seam = Seam(\n      api_key=\"your-api-key\",\n      wait_for_action_attempt=False,\n  )\n\n  seam.locks.unlock_door(device_id=device_id)\n\nor the behavior may be configured per-request:\n\n.. code-block:: python\n\n  seam.locks.unlock_door(\n      device_id=device_id,\n      wait_for_action_attempt=False,\n  )\n\nThe ``polling_interval`` and ``timeout`` may be configured for the client or per-request.\nFor example:\n\n.. code-block:: python\n\n  from seam import Seam, SeamActionAttemptFailedError, SeamActionAttemptTimeoutError\n\n  seam = Seam(\"your-api-key\")\n\n  lock = seam.locks.list()\n\n  if len(locks) == 0:\n      raise Exception(\"No locks in this workspace\")\n\n  lock = locks[0]\n\n  try:\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      print(\"Door unlocked\")\n  except SeamActionAttemptFailedError as e:\n      print(\"Could not unlock the door\")\n  except SeamActionAttemptTimeoutError as e:\n      print(\"Door took too long to unlock\")\n\nPagination\n~~~~~~~~~~\n\nSome Seam API endpoints that return lists of resources support pagination.\nUse the ``SeamPaginator`` class to fetch and process resources across multiple pages.\n\nManually fetch pages with the nextPageCursor\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. code-block:: python\n\n  from seam import Seam\n\n  seam = Seam()\n\n  paginator = seam.create_paginator(seam.devices.list, {\"limit\": 20})\n\n  devices, pagination = paginator.first_page()\n\n  if pagination.has_next_page:\n      more_devices, _ = paginator.next_page(pagination.next_page_cursor)\n\nResume pagination\n^^^^^^^^^^^^^^^^^\n\nGet the first page on initial load and store the state (e.g., in memory or a file):\n\n.. code-block:: python\n\n  import json\n  from seam import Seam\n\n  seam = Seam()\n\n  params = {\"limit\": 20}\n  paginator = seam.create_paginator(seam.devices.list, params)\n\n  devices, pagination = paginator.first_page()\n\n  # Example: Store state for later use (e.g., in a file or database)\n  pagination_state = {\n      \"params\": params,\n      \"next_page_cursor\": pagination.next_page_cursor,\n      \"has_next_page\": pagination.has_next_page,\n  }\n  with open(\"/tmp/seam_devices_list.json\", \"w\") as f:\n      json.dump(pagination_state, f)\n\nGet the next page at a later time using the stored state:\n\n.. code-block:: python\n\n  import json\n  from seam import Seam\n\n  seam = Seam()\n\n  # Example: Load state from where it was stored\n  with open(\"/tmp/seam_devices_list.json\", \"r\") as f:\n      pagination_state = json.load(f)\n\n  if pagination_state.get(\"has_next_page\"):\n      paginator = seam.create_paginator(\n          seam.devices.list, pagination_state[\"params\"]\n      )\n      more_devices, _ = paginator.next_page(\n          pagination_state[\"next_page_cursor\"]\n      )\n\nIterate over all resources\n^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. code-block:: python\n\n  from seam import Seam\n\n  seam = Seam()\n\n  paginator = seam.create_paginator(seam.devices.list, {\"limit\": 20})\n\n  for account in paginator.flatten():\n      print(account.account_type_display_name)\n\nReturn all resources across all pages as a list\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n.. code-block:: python\n\n  from seam import Seam\n\n  seam = Seam()\n\n  paginator = seam.create_paginator(seam.devices.list, {\"limit\": 20})\n\n  all_devices = paginator.flatten_to_list()\n\nInteracting with Multiple Workspaces\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSome Seam API endpoints interact with multiple workspaces. The ``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.. code-block:: python\n\n  # Pass as an option to the constructor\n  seam = SeamMultiWorkspace(personal_access_token=\"your-personal-access-token\")\n\n  # Use the factory method\n  seam = SeamMultiWorkspace.from_personal_access_token(\"your-personal-access-token\")\n\n  # List workspaces authorized for this Personal Access Token\n  workspaces = seam.workspaces.list()\n\nWebhooks\n~~~~~~~~\n\nThe Seam API implements webhooks using `Svix \u003chttps://www.svix.com\u003e`_.\nThis SDK exports a thin wrapper ``SeamWebhook`` around the svix package.\nUse it to parse and validate `Seam webhook events \u003chttps://docs.seam.co/latest/developer-tools/webhooks\u003e`_.\n\nRefer to the `Svix docs on Consuming Webhooks \u003chttps://docs.svix.com/receiving/introduction\u003e`_ for an in-depth guide on best-practices for handling webhooks in your application.\n\nThis example is for `Flask \u003chttps://flask.palletsprojects.com/\u003e`_,\nsee the `Svix docs for more examples in specific frameworks \u003chttps://docs.svix.com/receiving/verifying-payloads/how\u003e`_.\n\n.. code-block:: python\n\n  import os\n\n  from flask import Flask, request\n  from seam import SeamWebhook\n\n  app = Flask(__name__)\n\n  webhook = SeamWebhook(os.getenv('SEAM_WEBHOOK_SECRET'))\n\n  @app.route('/webhook', methods=['POST'])\n  def handle_webhook():\n      try:\n          data = webhook.verify(request.get_data(), request.headers)\n      except Exception:\n          return 'Bad Request', 400\n\n      try:\n          store_event(data)\n      except Exception:\n            return 'Internal Server Error', 500\n\n      return '', 204\n\n  def store_event(data):\n      print(data)\n\n  if __name__ == '__main__':\n      app.run(port=8080)\n\n\nAdvanced Usage\n~~~~~~~~~~~~~~\n\nSetting the endpoint\n^^^^^^^^^^^^^^^^^^^^\n\nSome contexts may need to override the API endpoint,\ne.g., testing or proxy setups.\n\nEither pass the ``endpoint`` option to the constructor, or set the ``SEAM_ENDPOINT`` environment variable.\n\nDevelopment and Testing\n-----------------------\n\nQuickstart\n~~~~~~~~~~\n\n::\n\n    $ git clone https://github.com/seamapi/python.git\n    $ cd pypackage\n    $ poetry install\n\nRun each command below in a separate terminal window:\n\n::\n\n    $ make watch\n\nPrimary development tasks are defined in the ``Makefile``.\n\nSource Code\n~~~~~~~~~~~\n\nThe `source code`__ is hosted on GitHub.\nClone the project with\n\n::\n\n    $ git clone https://github.com/seamapi/python.git\n\n.. __: https://github.com/seamapi/python\n\nRequirements\n~~~~~~~~~~~~\n\nYou will need `Python 3`_ and Poetry_ and Node.js_ with npm_.\n\nInstall the development dependencies with\n\n::\n\n    $ poetry install\n    $ npm install\n\n.. _Node.js: https://nodejs.org/\n.. _npm: https://www.npmjs.com/\n.. _Poetry: https://poetry.eustace.io/\n.. _Python 3: https://www.python.org/\n\nTests\n~~~~~\n\nLint code with\n\n::\n\n    $ make lint\n\n\nRun tests with\n\n::\n\n    $ make test\n\nRun tests on changes with\n\n::\n\n    $ make watch\n\nPublishing\n~~~~~~~~~~\n\nNew versions are created with `poetry version`_.\n\nAutomatic\n^^^^^^^^^\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\nManual\n^^^^^^\n\nPublish a new version by triggering a `version workflow_dispatch on GitHub Actions`_.\nThe ``version`` input will be passed as the first argument to `poetry version`_.\n\nThis may be done on the web or using the `GitHub CLI`_ with\n\n::\n\n    $ gh workflow run version.yml --raw-field version=\u003cversion\u003e\n\n.. _Poetry version: https://python-poetry.org/docs/cli/#version\n.. _GitHub CLI: https://cli.github.com/\n.. _version workflow_dispatch on GitHub Actions: https://github.com/seamapi/python/actions?query=workflow%3Aversion\n\nGitHub Actions\n--------------\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- ``PYPI_API_TOKEN``: API token for publishing on PyPI.\n\nThese must be set manually.\n\nSecrets for Optional GitHub Actions\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe version, format, generate, and semantic-release GitHub actions\nrequire a user with write access to the repository\nincluding access to read and write packages.\nSet these additional secrets to enable the action:\n\n- ``GH_TOKEN``: A personal access token for the user.\n- ``GIT_USER_NAME``: The name to set for Git commits.\n- ``GIT_USER_EMAIL``: The email to set for Git commits.\n- ``GPG_PRIVATE_KEY``: The `GPG private key`_.\n- ``GPG_PASSPHRASE``: The GPG key passphrase.\n\n.. _GPG private key: https://github.com/marketplace/actions/import-gpg#prerequisites\n\nContributing\n------------\n\nPlease submit and comment on bug reports and feature requests.\n\nTo submit a patch:\n\n1. Fork it (https://github.com/seamapi/python/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\nLicense\n-------\n\nThis Python package is licensed under the MIT license.\n\nWarranty\n--------\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%2Fpython","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fseamapi%2Fpython","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseamapi%2Fpython/lists"}