API reference
pyth_hermes
pyth-hermes: a Python client for the Pyth Network Hermes price-oracle API.
AsyncHermesClient
Asynchronous client for the Pyth Network Hermes API.
Adds :meth:stream_prices, an async iterator over the SSE price stream with
automatic reconnect + backoff. Mirrors :class:~pyth_hermes.HermesClient
for the request/response endpoints, and is an async context manager::
async with AsyncHermesClient() as client:
price = await client.get_price_decimal(feed_id)
As with the sync client, transient failures (429/5xx) are retried with
exponential backoff that honors Retry-After and the 60-second
rate-limit window.
base_url
property
The normalized API base URL in use (no trailing slash).
__init__(base_url=_BASE_URL_UNSET, *, api_key=None, api_key_header='Authorization', api_key_scheme='Bearer', timeout=30.0, max_retries=3, backoff_base=1.0, backoff_cap=60.0, client=None)
Construct an asynchronous Hermes client.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_url
|
str
|
API base URL. Defaults to production
( |
_BASE_URL_UNSET
|
api_key
|
Optional[str]
|
Optional API key. Optional today; mandatory for all callers from 2026-07-31. Sent on every request as a header. |
None
|
api_key_header
|
str
|
Header name to carry the API key. Defaults to
|
'Authorization'
|
api_key_scheme
|
str
|
Auth scheme prefix for the header value. Defaults to
|
'Bearer'
|
timeout
|
float
|
Per-request timeout in seconds. |
30.0
|
max_retries
|
int
|
Maximum retry attempts for transient errors, in addition to the initial attempt. |
3
|
backoff_base
|
float
|
Base seconds for exponential backoff between retries. |
1.0
|
backoff_cap
|
float
|
Maximum seconds any single backoff delay may reach. |
60.0
|
client
|
Optional[AsyncClient]
|
Optional preconfigured :class: |
None
|
Raises:
| Type | Description |
|---|---|
UserWarning
|
If both an explicit |
aclose()
async
Close the underlying async HTTP connection pool.
Called automatically when the client is used as an async context manager.
list_price_feeds(*, query=None, asset_type=None)
async
List the price-feed catalog, optionally filtered.
Async counterpart of :meth:~pyth_hermes.HermesClient.list_price_feeds.
Calls GET /v2/price_feeds; the search is fuzzy, so prefer
:meth:get_feed_id to resolve a single canonical feed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
Optional[str]
|
Case-insensitive substring to filter feeds by symbol. |
None
|
asset_type
|
Optional[str]
|
Asset class filter, e.g. |
None
|
Returns:
| Type | Description |
|---|---|
list[PriceFeed]
|
A list of :class: |
Raises:
| Type | Description |
|---|---|
HTTPStatusError
|
If the API returns a non-2xx status after retries are exhausted. |
get_feed_id(symbol)
async
Resolve a canonical feed id by EXACT attributes.symbol match.
Async counterpart of :meth:~pyth_hermes.HermesClient.get_feed_id. The
catalog search returns deprecated/variant feeds (MBTC, XBTC, ...)
and matches substrings, so this filters on exact symbol equality.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
symbol
|
str
|
The canonical symbol to match exactly, e.g.
|
required |
Returns:
| Type | Description |
|---|---|
Optional[str]
|
The 32-byte hex feed id, or |
Raises:
| Type | Description |
|---|---|
HTTPStatusError
|
If the underlying catalog request fails after retries are exhausted. |
get_latest_price(ids, *, parsed=True, encoding='hex')
async
Fetch the latest price update for one or more feed ids.
Async counterpart of :meth:~pyth_hermes.HermesClient.get_latest_price.
Calls GET /v2/updates/price/latest.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ids
|
list[str]
|
One or more 32-byte hex feed ids (sent as repeatable |
required |
parsed
|
bool
|
Whether to include decoded per-feed updates. When |
True
|
encoding
|
str
|
Encoding for the binary payload: |
'hex'
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
PriceUpdateResponse
|
class: |
Raises:
| Type | Description |
|---|---|
HTTPStatusError
|
If the API returns a non-2xx status after retries are exhausted. |
get_price_at(publish_time, ids, *, parsed=True, encoding='hex')
async
Fetch a historical price update at or just after a timestamp.
Async counterpart of :meth:~pyth_hermes.HermesClient.get_price_at.
Calls GET /v2/updates/price/{publish_time}; the API returns the
first update with a publish time at or after the requested timestamp.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
publish_time
|
int
|
Unix timestamp (seconds) to look up. |
required |
ids
|
list[str]
|
One or more 32-byte hex feed ids (sent as repeatable |
required |
parsed
|
bool
|
Whether to include decoded per-feed updates. |
True
|
encoding
|
str
|
Encoding for the binary payload: |
'hex'
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
PriceUpdateResponse
|
class: |
Raises:
| Type | Description |
|---|---|
HTTPStatusError
|
If the API returns a non-2xx status after retries are exhausted. |
get_price_decimal(feed_id)
async
Return the latest human-readable spot price for one feed id.
Async counterpart of
:meth:~pyth_hermes.HermesClient.get_price_decimal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
feed_id
|
str
|
A single 32-byte hex feed id. |
required |
Returns:
| Type | Description |
|---|---|
Decimal
|
The latest spot price as an exact :class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the API returns no parsed price for |
HTTPStatusError
|
If the API returns a non-2xx status after retries are exhausted. |
stream_prices(ids, *, parsed=True, reconnect=True)
async
Stream live price updates over Server-Sent Events (SSE).
Opens GET /v2/updates/price/stream and yields one
:class:~pyth_hermes.models.PriceUpdateResponse per event. With
reconnect=True (the default) the stream transparently re-opens after
a disconnect or transient error, applying exponential backoff between
attempts (the backoff counter resets after each successful connect). With
reconnect=False the iterator stops when the server closes the stream
and re-raises transport/HTTP errors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ids
|
list[str]
|
One or more 32-byte hex feed ids to subscribe to (sent as
repeatable |
required |
parsed
|
bool
|
Whether each event should include decoded per-feed updates. |
True
|
reconnect
|
bool
|
Whether to automatically reconnect with backoff after a
disconnect or transient error. Defaults to |
True
|
Yields:
| Name | Type | Description |
|---|---|---|
A |
AsyncIterator[PriceUpdateResponse]
|
class: |
Raises:
| Type | Description |
|---|---|
HTTPStatusError
|
On a non-2xx stream response when
|
TransportError
|
On a connection failure when
|
Example
btc = "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43" async with AsyncHermesClient() as client: ... async for update in client.stream_prices([btc]): ... if update.parsed: ... print(update.parsed[0].to_decimal()) ... break # stop after the first tick
HermesClient
Synchronous client for the Pyth Network Hermes API.
Get a BTC/USD price in a few lines::
from pyth_hermes import HermesClient
client = HermesClient()
feed_id = client.get_feed_id("Crypto.BTC/USD")
print(client.get_price_decimal(feed_id))
An api_key and custom base_url may be supplied for paid providers
and for the mandatory-key requirement landing 2026-07-31. The client is also
a context manager, which closes the underlying HTTP connection on exit::
with HermesClient() as client:
...
Transient failures (HTTP 429 and 5xx) are retried automatically with
exponential backoff that honors any Retry-After header and respects the
60-second rate-limit window.
base_url
property
The normalized API base URL in use (no trailing slash).
__init__(base_url=_BASE_URL_UNSET, *, api_key=None, api_key_header='Authorization', api_key_scheme='Bearer', timeout=30.0, max_retries=3, backoff_base=1.0, backoff_cap=60.0, client=None)
Construct a synchronous Hermes client.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_url
|
str
|
API base URL. Defaults to production
( |
_BASE_URL_UNSET
|
api_key
|
Optional[str]
|
Optional API key. Optional today; mandatory for all callers from 2026-07-31. Sent on every request as a header. |
None
|
api_key_header
|
str
|
Header name to carry the API key. Defaults to
|
'Authorization'
|
api_key_scheme
|
str
|
Auth scheme prefix for the header value. Defaults to
|
'Bearer'
|
timeout
|
float
|
Per-request timeout in seconds. |
30.0
|
max_retries
|
int
|
Maximum retry attempts for transient errors (429/5xx and transport errors), in addition to the initial attempt. |
3
|
backoff_base
|
float
|
Base seconds for exponential backoff between retries. |
1.0
|
backoff_cap
|
float
|
Maximum seconds any single backoff delay may reach. |
60.0
|
client
|
Optional[Client]
|
Optional preconfigured :class: |
None
|
Raises:
| Type | Description |
|---|---|
UserWarning
|
If both an explicit |
close()
Close the underlying HTTP connection pool.
Called automatically when the client is used as a context manager.
list_price_feeds(*, query=None, asset_type=None)
List the price-feed catalog, optionally filtered.
Calls GET /v2/price_feeds. Note the search is fuzzy and returns
deprecated/variant feeds; for resolving a single canonical feed prefer
:meth:get_feed_id, which matches on exact symbol.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
Optional[str]
|
Case-insensitive substring to filter feeds by symbol. |
None
|
asset_type
|
Optional[str]
|
Asset class filter, e.g. |
None
|
Returns:
| Type | Description |
|---|---|
list[PriceFeed]
|
A list of :class: |
Raises:
| Type | Description |
|---|---|
HTTPStatusError
|
If the API returns a non-2xx status after retries are exhausted. |
get_feed_id(symbol)
Resolve a canonical feed id by EXACT attributes.symbol match.
GET /v2/price_feeds?query=... returns deprecated/variant feeds
(MBTC, XBTC, ...) first and matches substrings, so this filters
on exact symbol equality to avoid picking the wrong feed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
symbol
|
str
|
The canonical symbol to match exactly, e.g.
|
required |
Returns:
| Type | Description |
|---|---|
Optional[str]
|
The 32-byte hex feed id, or |
Raises:
| Type | Description |
|---|---|
HTTPStatusError
|
If the underlying catalog request fails after retries are exhausted. |
Example
client.get_feed_id("Crypto.BTC/USD") 'e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43'
get_latest_price(ids, *, parsed=True, encoding='hex')
Fetch the latest price update for one or more feed ids.
Calls GET /v2/updates/price/latest.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ids
|
list[str]
|
One or more 32-byte hex feed ids (sent as repeatable |
required |
parsed
|
bool
|
Whether to include decoded per-feed updates. When |
True
|
encoding
|
str
|
Encoding for the binary payload: |
'hex'
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
PriceUpdateResponse
|
class: |
PriceUpdateResponse
|
payload and (when |
Raises:
| Type | Description |
|---|---|
HTTPStatusError
|
If the API returns a non-2xx status after retries are exhausted. |
Example
btc = "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43" resp = client.get_latest_price([btc]) resp.parsed[0].to_decimal() Decimal('63952.82153102')
get_price_at(publish_time, ids, *, parsed=True, encoding='hex')
Fetch a historical price update at or just after a timestamp.
Calls GET /v2/updates/price/{publish_time}; the API returns the
first update with a publish time greater than or equal to the requested
timestamp.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
publish_time
|
int
|
Unix timestamp (seconds) to look up. |
required |
ids
|
list[str]
|
One or more 32-byte hex feed ids (sent as repeatable |
required |
parsed
|
bool
|
Whether to include decoded per-feed updates. |
True
|
encoding
|
str
|
Encoding for the binary payload: |
'hex'
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
PriceUpdateResponse
|
class: |
Raises:
| Type | Description |
|---|---|
HTTPStatusError
|
If the API returns a non-2xx status after retries are exhausted. |
get_price_decimal(feed_id)
Return the latest human-readable spot price for one feed id.
Convenience wrapper over :meth:get_latest_price that returns just the
spot price as a :class:~decimal.Decimal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
feed_id
|
str
|
A single 32-byte hex feed id. |
required |
Returns:
| Type | Description |
|---|---|
Decimal
|
The latest spot price as an exact |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the API returns no parsed price for |
HTTPStatusError
|
If the API returns a non-2xx status after retries are exhausted. |
BinaryUpdate
Bases: BaseModel
The encoded binary VAA/update payload.
This is the on-chain-submittable blob; data is a list of encoded
strings whose representation is given by encoding.
FeedAttributes
Bases: BaseModel
Attributes block of a price feed catalog entry.
The Hermes attributes object is an open string map; the well-known keys
are surfaced as typed fields and any extra keys are preserved (accessible
via :attr:pydantic.BaseModel.model_extra).
ParsedPriceUpdate
Bases: BaseModel
A single parsed price update for one feed id.
Carries both the spot price and the exponentially-weighted moving
average ema_price. Call :meth:to_decimal for the human-readable spot
price.
to_decimal()
Return the human-readable spot price as a :class:~decimal.Decimal.
Shortcut for self.price.to_decimal().
PriceFeed
Bases: BaseModel
A single price feed catalog entry from GET /v2/price_feeds.
symbol
property
Shortcut to attributes.symbol (e.g. "Crypto.BTC/USD").
Returns:
| Type | Description |
|---|---|
Optional[str]
|
The canonical symbol, or |
PriceFeedMetadata
Bases: BaseModel
Metadata attached to a parsed price update.
All fields are optional; Hermes may omit any of them depending on the endpoint and whether proof data is available.
PriceUpdateResponse
Bases: BaseModel
Response from the latest / historical price update endpoints.
Returned by GET /v2/updates/price/latest and
GET /v2/updates/price/{publish_time}, and by each SSE stream event.
parsed is None when the request was made with parsed=False.
RpcPrice
Bases: BaseModel
A single price reading with its exponent and publish time.
Used for both the spot price and the ema_price of a parsed update.
The price/conf fields are raw integers; apply expo (or call
:meth:to_decimal / :meth:conf_to_decimal) to get human-readable values.
to_decimal()
Return the human-readable price as a :class:~decimal.Decimal.
Returns:
| Type | Description |
|---|---|
Decimal
|
|
conf_to_decimal()
Return the confidence interval as a :class:~decimal.Decimal.
Uses the same exponent as the price.
Returns:
| Type | Description |
|---|---|
Decimal
|
|
price_to_decimal(price, expo)
Convert a raw Pyth price + exponent into a real Decimal value.
Pyth reports prices as a large integer plus a (usually negative) base-10
exponent. The human-readable value is price * 10 ** expo, computed here
with :class:~decimal.Decimal to avoid binary float imprecision.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
price
|
Union[int, str]
|
The raw integer price, as an |
required |
expo
|
int
|
The base-10 exponent to apply (e.g. |
required |
Returns:
| Type | Description |
|---|---|
Decimal
|
The exact human-readable price as a :class: |
Example
price_to_decimal(6395282153102, -8) Decimal('63952.82153102')