Skip to main content

OpenHandle Python SDK

The official Python client for the OpenHandle API.

Installation

pip install openhandle

The package supports Python 3.10 and newer and ships full type annotations.

Usage

Create a Test key in the Openhandle dashboard, store it as OPENHANDLE_TEST_KEY, and create one reusable client:

import os

from openhandle import OpenHandle

openhandle = OpenHandle(api_key=os.environ["OPENHANDLE_TEST_KEY"])
profile = openhandle.instagram.profile("northstar_forge_test")

response = profile.get()
posts = profile.posts.list(freshness="24h")

print(response.data["handle"], len(posts.data))

The key selects the environment. oh_test_ keys return deterministic synthetic data with a $0.000 actual charge; oh_live_ keys use real public identifiers and normal billing. Never expose an API key in client-side code.

See the API reference for a typed SDK example for every operation.

Resource selection

The SDK follows one predictable grammar:

openhandle.<platform>.<resource>(reference).<subresource>.<operation>(options)

Only terminal operations such as get, list, search, and fetch perform network requests. Selecting a resource is synchronous and reusable:

post = openhandle.instagram.post("Db04otPRpRH")

response = post.get()
comments = post.comments.list()

A profile selector accepts a username shorthand or an explicit reference:

openhandle.instagram.profile("openai")
openhandle.instagram.profile("https://www.instagram.com/openai/")
openhandle.instagram.profile(username="12356")
openhandle.instagram.profile(id="25025320")
openhandle.instagram.profile(url="https://www.instagram.com/openai/")

A raw string is never treated as a platform ID. profile("12356") selects the username 12356; profile(id="12356") selects platform ID 12356. Numeric reference values are rejected because platform IDs are opaque strings.

Call openhandle.fetch(url) when you do not know which resource a supported social URL represents.

Pagination

A list or search operation returns one typed page:

page = openhandle.instagram.profile("northstar_forge_test").posts.list()

print(page.data, page.has_next_page, page.next_cursor)
next_page = page.next()

items() iterates lazily across pages, one request per page:

for post in openhandle.instagram.profile("northstar_forge_test").posts.items():
    print(post["id"])

Async client

AsyncOpenHandle exposes the same resource graph with async terminal operations:

import asyncio
import os

from openhandle import AsyncOpenHandle


async def main() -> None:
    async with AsyncOpenHandle(api_key=os.environ["OPENHANDLE_TEST_KEY"]) as openhandle:
        response = await openhandle.instagram.profile("northstar_forge_test").get()
        print(response.data["handle"])

        async for post in openhandle.instagram.profile("northstar_forge_test").posts.items():
            print(post["id"])


asyncio.run(main())

Responses

Every response preserves the public envelope. data stays typed through the generated models in openhandle.models, and metadata is available on the response object:

response = openhandle.instagram.profile("northstar_forge_test").get()

response.platform  # "instagram"
response.resource  # "profile"
response.captured_at  # datetime
response.source  # "live" or "cache"
response.request_id  # stable request identifier for logs and support
response.billing.cost  # authoritative charge as a decimal string

A missing metric is None. It is never 0.

Errors and retries

The SDK raises OpenHandleError with the documented fields. Branch on code, never on message:

from openhandle import OpenHandle, OpenHandleError

try:
    response = openhandle.instagram.profile("private_account").get()
except OpenHandleError as error:
    print(error.code, error.request_id, error.retryable)

Retryable failures are retried automatically with capped exponential backoff and Retry-After support. Configure the client, or override per request:

openhandle = OpenHandle(api_key="...", timeout=10.0, max_retries=1)
openhandle.twitter.profile("openai").get(timeout=5.0, max_retries=0)

Locally invalid references raise OpenHandleReferenceError before any request is made. ReferenceMismatchError reports a social URL that belongs to a different platform or resource than the selector.

License

MIT

Release files for openhandle 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for openhandle 1.0.0
File Size Uploaded
openhandle-1.0.0.tar.gz 41.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for openhandle 1.0.0
File Interpreter ABI Platform
openhandle-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 86.2 kB

Release files / openhandle-1.0.0.tar.gz

Download URL openhandle-1.0.0.tar.gz
Size 41.8 kB
Tags Source
SHA-256 checksum
How to use checksums
1ad58388d6359621214748f046f42d6723364f1e193dbfa7bc7cfdfc1459f587
BLAKE2b-256 checksum
How to use checksums
4d9f103f1e3dcdbc4ee0c3aaf946e44464bd9a843a3e58ce56c1d572c76b6b1b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 30, 2026.

Transparency log

Release files / openhandle-1.0.0-py3-none-any.whl

Download URL openhandle-1.0.0-py3-none-any.whl
Size 44.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a1f6c2fe769dbc120007bc842672541c809ef5144912460e60ca9dcf6590786b
BLAKE2b-256 checksum
How to use checksums
924a9b7ae13bf16a6eb894a07c0283ef1a4bb8a44fe8063d9855ad50545944bc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 30, 2026.

Transparency log

Release history Release notifications | RSS feed

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.2

2 release files

1.0.1

2 release files

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page