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.1.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.1.0
File Size Uploaded
openhandle-1.1.0.tar.gz 48.1 kB Details

Built distribution (wheel)

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

Total release size: 98.8 kB

Release files / openhandle-1.1.0.tar.gz

Download URL openhandle-1.1.0.tar.gz
Size 48.1 kB
Tags Source
SHA-256 checksum
How to use checksums
bdc9a5409dcce6db87f0ee56e6da2c89b6f664cb069a1bacb48748e87b75e3b0
BLAKE2b-256 checksum
How to use checksums
02b2f515b832be4cba3086942c56297b09e21a36620f21bda29df0fd8fb0f807
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 17, 2026.

Transparency log

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

Download URL openhandle-1.1.0-py3-none-any.whl
Size 50.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
323b9e24ed138744a92996a9f40de0b9af75f74d642625657d3f1e54af8e21fe
BLAKE2b-256 checksum
How to use checksums
7c58b50e7ec474f30b0a3f569ca5fd0669e0cb62209a09c524e4f4c44c1dd370
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 17, 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

This release

1.1.0 This release

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