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. TikTok short links such as tiktok.com/t/… and vm.tiktok.com/… are rejected by selectors and only work through fetch, which expands them server-side.

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.2.2

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.2.2
File Size Uploaded
openhandle-1.2.2.tar.gz 48.2 kB Details

Built distribution (wheel)

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

Total release size: 98.9 kB

Release files / openhandle-1.2.2.tar.gz

Download URL openhandle-1.2.2.tar.gz
Size 48.2 kB
Tags Source
SHA-256 checksum
How to use checksums
5f70f0c662720d2600b1f93fb7119fbe196bf73319d7d793f16982b148da3cdc
BLAKE2b-256 checksum
How to use checksums
a0773b06a715b61d3c69ed2a32c40d78b28d1c9860be167a33ec6107f3926b63
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 Sep 25, 2026.

Transparency log

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

Download URL openhandle-1.2.2-py3-none-any.whl
Size 50.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
59c31a951bb9c6dec590fe13cdc9a870eeb8b29b89cccfebaf08a67ed4e57057
BLAKE2b-256 checksum
How to use checksums
d245a2d83242619dc78b7d75cc0eb022a87cf5b8954b37c0ec8da3838172a506
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 Sep 25, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.2.2 This release

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

1.0.0

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