palanor
The Python client for Palanor Data: the signals, Custom Indices and refined datasets of the Palanor lattice, with the provenance of every value kept on the result.
- One typed client over the REST API at
https://api.palanor.com/v1 - Pages are followed for you;
max_rowscaps a long read - Retries with exponential backoff on transient errors (429, 502, 503, 504, database timeouts)
to_pandas()on every result, with provenance kept indf.attrs- Python 3.9+, one dependency (
httpx); pandas is optional
Install
pip install "https://palanor.com/developers/python/palanor-0.1.0-py3-none-any.whl"
# with DataFrames:
pip install "palanor[pandas] @ https://palanor.com/developers/python/palanor-0.1.0-py3-none-any.whl"
Mint a free key at palanor.com/api-tokens (1,000 requests a month, no card), then:
export PALANOR_API_KEY="plnr_..."
Quickstart
from palanor import Palanor
p = Palanor() # reads PALANOR_API_KEY; or Palanor(api_key="plnr_...")
# A series over a window: every page joined, oldest first
spread = p.signals.observations("rates.spread_2y10y", start="2020-01-01", end="2024-12-31")
print(len(spread), spread.observations[-1])
print(spread.provenance.attribution) # the credit line owed when you show it
df = spread.to_pandas() # DatetimeIndex, one "value" column
df.attrs["provenance"]["license_class"] # 'public_domain'
# The latest reading, and where it stands in its own record
cpi = p.signals.get("bls_cpi_college_tuition", history=12)
cpi.latest.value, cpi.latest.date, cpi.context["percentile"]
What you can read
| Method | Endpoint | Notes |
|---|---|---|
p.signals.list(category=None) |
/v1/signals |
Every public signal the API serves, each row with provenance |
p.signals.get(slug, history=30, vintage="latest") |
/v1/signals/{slug} |
Definition, latest, context, up to 365 recent observations |
p.signals.latest(slug) |
/v1/signals/{slug} |
Just the latest observation |
p.signals.observations(slug, start, end, vintage="latest") |
/v1/signals/{slug}/observations |
Any window, paged in 1,000s |
p.indices.list() / p.currents.list() |
/v1/indices, /v1/currents |
Palanor Custom Indices; the Currents |
p.guidance.list(ticker=, metric=, since=) |
/v1/guidance |
Guidance Ledger |
p.risk_factors.list(ticker=, since=, category=, change_type=) |
/v1/risk-factors |
10-K risk factor changes |
p.events.list(ticker, items=, since=, until=) |
/v1/events |
Material events from 8-K item codes |
p.insiders.list(ticker, since=, codes=) |
/v1/insiders |
Forms 3, 4, 5 |
p.ownership.get(ticker, period=, limit=) |
/v1/ownership |
13F holders and 13D/G 5% owners |
p.compensation.get(ticker) |
/v1/compensation |
Pay versus performance |
p.fails.get(ticker, since=) |
/v1/fails |
SEC fails-to-deliver (not short interest) |
p.contracts.get(ticker) / p.lobbying.get(ticker) / p.patents.get(ticker) |
/v1/contracts, /v1/lobbying, /v1/patents |
USAspending, LDA, USPTO |
p.industries.sectors() / .search(q) / .get(naics) |
/v1/industries |
US industry sizing (Census, BEA, BLS) |
p.release_calendar.list(start, end) |
/v1/release-calendar |
US economic release calendar |
p.almanac.list() / p.wire.list() |
/v1/almanac, /v1/wire |
Almanac posts; the Wire (Pro keys) |
p.get(path, **params) |
anything | Raw access to any endpoint |
Company datasets cover the S&P 500 and take a ticker ("AAPL") or cik=.
own = p.ownership.get("AAPL", limit=10)
own.to_pandas() # the 13F holders, largest first
own["five_percent_holders"] # read any field like a dict
own.provenance # {"holders": {...}, "five_percent_holders": {...}}
events = p.events.list("MSFT", items=["1.05", "5.02"], since="2024-01-01")
events.to_pandas()[["filed_at", "item_code", "category"]]
tgt = p.guidance.list(ticker="TGT", metric="eps_adjusted")
Provenance
The API serves a value only when its source may be redistributed, and it says so on the value.
Signal.provenanceandSeries.provenanceare aProvenance:source,publisher,license_class,license_name,license_url,attributionandredistributable.Result.provenanceis the response's block as sent. Rows that carry their own block keep it, andto_pandas()flattens it toprovenance.source,provenance.license_classand so on.Result.provenance_blocks()lists every distinct block in a response.
Show the attribution line wherever you display the data. Terms: palanor.com/terms.
First-reported values
vintage="first" asks for each observation as first published, before revisions. Those values come from
ALFRED (Federal Reserve Bank of St. Louis), which isn't licensed for redistribution today, so the call
raises PermissionDeniedError. They are shown in the Palanor Terminal.
Errors, retries and your allowance
Every call counts against the key's monthly allowance. result.rate_limit (and p.last_rate_limit) show
the tier, the cap and what's left.
| Exception | When |
|---|---|
AuthenticationError |
No key, a wrong key, or a revoked key (401) |
PermissionDeniedError |
The tier doesn't include the endpoint, or the data can't be redistributed (402, 403) |
NotFoundError |
No such signal or company, or a signal whose source is display-only (404) |
BadRequestError |
A malformed parameter (400) |
QuotaExceededError |
The month's cap is spent (429). Not retried. |
RateLimitError |
A transient 429 that outlasted the retries |
ServerError / APIConnectionError |
5xx, or the API couldn't be reached |
Transient failures are retried up to max_retries times (default 3). The wait doubles from backoff
seconds (default 0.5) with jitter, and a Retry-After header is honoured.
p = Palanor(max_retries=5, backoff=1.0, timeout=60)
Development
cd packages/palanor-python
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytest -m "not live" # offline: transport, retries, paging, DataFrames
PALANOR_API_KEY=plnr_... pytest -m live # the live API, about 30 requests
mypy # strict
MIT licensed (the client code). The data is governed by palanor.com/terms and by the license in each result's provenance block.
Release files for palanor 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| palanor-0.1.0.tar.gz | 19.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| palanor-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 36.2 kB
Release files / palanor-0.1.0.tar.gz
| Download URL | palanor-0.1.0.tar.gz |
|---|---|
| Size | 19.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0a2fe7658da3fea7dee8c48c1cd6c5d0c2ea937bb6378a5ad3ac642e736a3249
|
|
BLAKE2b-256 checksum How to use checksums |
18d4c4ed06cccfd38db13170cd398f54a4bcb18622c26db9dd03a45385ec9453
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|
Release files / palanor-0.1.0-py3-none-any.whl
| Download URL | palanor-0.1.0-py3-none-any.whl |
|---|---|
| Size | 17.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
63aba8fb63812fbc49378e0f38b3b8f6b8087e098d177d30d68e27639dee0b5a
|
|
BLAKE2b-256 checksum How to use checksums |
b6eef91995a54a6a5d168dce86d5b7420261853ed1e5c822ce72c4a2ee69fdb6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.6
|