Skip to main content

certvas — Python SDK

Point-in-time, license-clean African & emerging-market data and signals, in three lines.

pip install certvas          # add pandas for DataFrames: pip install "certvas[pandas]"
import certvas
cv = certvas.Client(api_key="...")                 # free sample key: https://certvas.com/signup.html
panel = cv.signals.procurement_demand(country="ZA", as_of="2025-06-30")

panel is a pandas DataFrame (or a list of dicts if pandas isn't installed). Every response carries provenance and a license class; point-in-time endpoints honour as_of with no look-ahead.

What you can call

# The flagship signal — government-demand share, buyer concentration, 3-month momentum, point-in-time
cv.signals.procurement_demand(country="ZA", as_of="2025-06-30", category="services")

# Underlying datasets
cv.tenders(country="ZA", from_="2024-01-01")
cv.macro(series="FX.ZAR.USD", as_of="2025-06-30")   # point-in-time macro
cv.macro(country="NGA", indicator="FP.CPI.TOTL.ZG")  # annual macro

# Fundamentals for one issuer, point-in-time (Woolworths Holdings, JSE)
cv.fundamentals("DC4D39BDF1A9471A472810CB32", as_of="2024-02-01", period_type="FY")
cv.fundamentals("DC4D39BDF1A9471A472810CB32", as_reported=True)       # originally filed — use this for a backtest
cv.fundamentals("DC4D39BDF1A9471A472810CB32", all_vintages=True)      # every restatement, for revision analysis

as_of on fundamentals is a real no-look-ahead read

It filters on two dates, and the second is the one that matters:

period_end <= as_of the reporting period had ended
available_at <= as_of the number had actually been published

FY results for a December year-end are typically not public for another 60–120 days. Filtering on the period alone hands you numbers nobody had at the time — the classic look-ahead bias. Where an announcement date could not be evidenced, available_at falls back to the date Certvas captured the value, which is always later than true publication for a backfilled filing. So the fallback can only ever exclude a row from your window, never admit one early: weak coverage costs you recall, not correctness.

Three reads, three different questions. Fundamentals is append-only across restatements, so an issuer × period × line item can hold several rows:

call returns use it for
(default) latest vintage available by as_of what the tape said on that date
as_reported=True the originally filed value factor studies and backtests
all_vintages=True every vintage, with restated / vintage_seq / superseding_record_ref revision analysis

Reach for as_reported=True in any historical study. Running one on latest-value history is restatement bias: those numbers were revised with hindsight and were never on the tape at the time you are pretending to trade. The same values ship as fundamentals_as_reported in the bulk AF-FUND package.

Everything else

# Raw escape hatch for any endpoint — returns the full JSON envelope
cv.get("/v1/quality-metrics/af-tender")

Provenance on every value

The DataFrame carries the license notice and query metadata in df.attrs:

panel.attrs["_license"]   # the license-clean notice
panel.attrs["as_of"]      # the point-in-time date you queried
panel.attrs["count"]

One shape for every dataset: entity + fact + provenance

certvas.shared puts AF-FUND, AF-TENDER and AF-MACRO in one layout: shared_entity (issuers, public buyers and countries), shared_fact (one row per value, with available_at, the point-in-time column) and shared_provenance (the source and licence of every fact). It runs locally over the Parquet release you receive, so nothing extra is hosted or billed:

# pip install "certvas[shared]"
import duckdb
from certvas import shared

con = duckdb.connect()
shared.register_release(con, "path/to/release")      # the folder holding gold_*.parquet
shared.build(con)
con.sql("select * from shared_fact where available_at <= date '2025-06-30'").df()

The API serves the same rows from the live tables, with provenance on each row:

cv.shared_facts(entity_id="DC4D39BDF1A9471A472810CB32", as_of="2025-06-30")   # an issuer, AF-FUND
cv.shared_facts(entity_id="ZAF")                                              # a country, AF-MACRO
cv.shared_facts(country="KEN", dataset="AF-TENDER", limit=100)                # tender values
cv.shared_facts(entity_id="DC9C8E68C8A893E1142B0D9806", dataset="AF-TENDER")  # awards an issuer won (Fidson Healthcare)

From a fundamentals response instead: shared.from_api_fundamentals(cv.fundamentals("DC...", as_of="2025-06-30")). Every column is described in shared.SPEC. Nothing is estimated, a restatement is a new vintage, available_at is NULL rather than guessed, and a tender buyer carries a Certvas ID only where it was resolved.

Upgrading in-band

Sample-tier keys are capped. Over-ask and the SDK raises certvas.UpgradeRequired with the checkout URL, so an agent or script can upgrade without leaving the flow:

try:
    cv.signals.procurement_demand(limit=100_000)
except certvas.UpgradeRequired as e:
    print("Upgrade:", e.checkout_url)

Errors

  • certvas.AuthError — missing/invalid key (401)
  • certvas.UpgradeRequired — this request has a price (402); carries .checkout_url and .docs. Raised when a sample key explicitly asks past its per-request row cap. At API v2 the same condition returns 429 and this exception will be raised for that too, so catching UpgradeRequired is the forward-compatible way to handle it — do not branch on the raw status.
  • certvas.CertvasError — base class for everything else

Docs: https://certvas.com/developers.html · Signals: https://certvas.com/signals/

Release files for certvas 0.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 certvas 0.1.0
File Size Uploaded
certvas-0.1.0.tar.gz 23.8 kB Details

Built distribution (wheel)

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

Total release size: 42.1 kB

Release files / certvas-0.1.0.tar.gz

Download URL certvas-0.1.0.tar.gz
Size 23.8 kB
Tags Source
SHA-256 checksum
How to use checksums
517efab37fa250c9799b592558628f83402ec7a4a98735928e9cdde2fbbd2091
BLAKE2b-256 checksum
How to use checksums
9b0ee67cb79d9c8b6f81c811af0198bab5ed58f005c09f62135511e4d56e4696
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 24, 2026.

Transparency log

Release files / certvas-0.1.0-py3-none-any.whl

Download URL certvas-0.1.0-py3-none-any.whl
Size 18.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
72d1df58bba127e018b9e65e46cff5f90f7855f488ac826fbdea8e40ba968e16
BLAKE2b-256 checksum
How to use checksums
0d2a1ee81d51375f46c7d64476d024a489cf28150674b83a61ae4a710328b909
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 24, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

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