pyth-hermes
A typed Python client for the Pyth Network Hermes price-oracle API. Sync and async clients, Pydantic v2 models, Server-Sent-Events price streaming with auto-reconnect, and a Decimal price helper.
- Sync (
HermesClient) and async (AsyncHermesClient) APIs overhttpx - SSE streaming with reconnect + backoff
- Graceful 429 rate-limit handling (retries that respect the 60s window)
- Configurable
base_url(production, beta, or paid providers) and optional API key from day one mypy --strictclean, fully type-hinted, shipspy.typed
Install
pip install pyth-hermes
# with the optional pandas helper:
pip install "pyth-hermes[pandas]"
Quickstart — BTC/USD price in under 5 lines
from pyth_hermes import HermesClient
client = HermesClient()
feed_id = client.get_feed_id("Crypto.BTC/USD") # exact-symbol lookup
print(client.get_price_decimal(feed_id)) # -> Decimal("63952.82...")
Async + streaming
import asyncio
from pyth_hermes import AsyncHermesClient
BTC = "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"
async def main():
async with AsyncHermesClient() as client:
async for update in client.stream_prices([BTC]):
print(update.parsed[0].to_decimal())
asyncio.run(main())
Historical price
resp = client.get_price_at(1718900000, [BTC]) # unix timestamp
print(resp.parsed[0].to_decimal())
pandas
from pyth_hermes.pandas import updates_to_dataframe
df = updates_to_dataframe([client.get_latest_price([BTC])])
Prices and exponents
Pyth returns integer prices plus an exponent. The real value is price * 10**expo, computed exactly as a Decimal:
from pyth_hermes import price_to_decimal
price_to_decimal(6395282153102, -8) # Decimal("63952.82153102")
RpcPrice.to_decimal() and ParsedPriceUpdate.to_decimal() are convenience wrappers.
Finding feed ids — use the EXACT symbol
/v2/price_feeds?query=btc returns deprecated / variant feeds (e.g. MBTC, XBTC) before the canonical one and matches substrings. get_feed_id() therefore matches on exact attributes.symbol:
client.get_feed_id("Crypto.BTC/USD")
# -> "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43"
🔴 Authentication (changes 2026-07-31)
Today the public endpoint needs no API key. From 2026-07-31 an API key becomes mandatory. This client accepts one from day one — pass it now to be ready:
client = HermesClient(api_key="YOUR_KEY") # default: Authorization: Bearer YOUR_KEY
The exact header is not finalized publicly, so both the header name and scheme are configurable:
HermesClient(api_key="KEY", api_key_header="X-Api-Key", api_key_scheme="") # -> X-Api-Key: KEY
Endpoints / base URLs
from pyth_hermes import HermesClient
HermesClient() # production: https://hermes.pyth.network
HermesClient(base_url="https://hermes-beta.pyth.network") # beta
HermesClient(base_url="https://your-paid-provider.example") # Triton / P2P / extrnode / Liquify
You may also inject your own preconfigured httpx.Client / httpx.AsyncClient via client=... (e.g. for custom transports, proxies, or connection pools). In that case the request host is taken from your client, so set base_url on the client itself — passing both base_url= and client= raises a UserWarning because the constructor's base_url would be a no-op. The api_key is still applied per-request, so it works with an injected client.
import httpx
from pyth_hermes import HermesClient
http = httpx.Client(base_url="https://your-paid-provider.example", proxy="http://localhost:8080")
client = HermesClient(api_key="KEY", client=http) # base_url comes from `http`
Rate limits
The public endpoint allows 10 requests / 10 seconds per IP. Exceeding it returns HTTP 429 for the next 60 seconds. The client retries 429 and 5xx responses with exponential backoff + jitter, honoring any Retry-After header and never exceeding the 60s rate-limit window per delay. Tune via max_retries, backoff_base, backoff_cap.
Not implemented
The TWAP endpoints (/v2/updates/twap/...) are intentionally omitted — the API returns HTTP 400 "deprecated and no longer available".
Development
pip install -e ".[dev]"
pytest # unit tests (no network)
pytest -m integration # live smoke tests against production
mypy
ruff check .
License
MIT
Metadata
Release files for pyth-hermes 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyth_hermes-0.1.1.tar.gz | 21.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyth_hermes-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 40.1 kB
Release files / pyth_hermes-0.1.1.tar.gz
| Download URL | pyth_hermes-0.1.1.tar.gz |
|---|---|
| Size | 21.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
db022f6d588e4ef593c4e89db34056a8c242d443fa4d42157a35968d8fe18a9f
|
|
BLAKE2b-256 checksum How to use checksums |
76922255f959c9b196ffd9cb696fac018e38c6d3f10ef9cc37061b28557ed6e6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.9
|
Release files / pyth_hermes-0.1.1-py3-none-any.whl
| Download URL | pyth_hermes-0.1.1-py3-none-any.whl |
|---|---|
| Size | 18.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
327381b82262ba59a26d88b641ba348ec9faea129f4125bc017fcb5534b92441
|
|
BLAKE2b-256 checksum How to use checksums |
b13ac49feb6fa1b8b25f5a8ff040e318d9d83ca66bff75e07c023794a63c6a40
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.9
|