Skip to main content

Arche Python SDK

Typed, production-grade Python SDK for Arche public data APIs.

This initial release covers the primary public data surface:

  • Companies
  • Filings
  • Statements
  • Narratives
  • Bulk export (Scale and Enterprise plans)

It does not include protected control-plane, billing, org/team/project/environment admin, usage, webhook, MCP, or internal ops routes.

Installation

pip install arche-sdk

For local monorepo usage:

pip install -e sdks/python

Authentication

API key

from arche_sdk import ArcheClient

client = ArcheClient(api_key="your_api_key")

Bearer token for protected portal/control-plane routes

from arche_sdk import ArcheClient

client = ArcheClient(bearer_token="your_jwt_or_token")

Use bearer auth only for protected portal/control-plane or internal routes that explicitly require it. Public runtime API examples and quickstarts should use api_key.

api_key and bearer_token are mutually exclusive; passing both raises ValueError.

Quickstart

Companies

from arche_sdk import ArcheClient

with ArcheClient(api_key="...") as client:
    company = client.companies.get("0000320193")
    resolved = client.companies.resolve("AAPL")
    completeness = client.companies.get_completeness("0000320193")

Naming a company

Every method that takes a cik also accepts a ticker symbol in its place, and a ciks list accepts tickers. Digits are sent as a CIK and anything else as a ticker, which the API resolves to the company whose filings hold its statements on the request's date; one list must hold CIKs only or tickers only. A company_id (narratives) takes the company UUID, the CIK or the ticker.

with ArcheClient(api_key="...") as client:
    versions = client.statements.list("AAPL", statement_type="INCOME_STATEMENT")
    derived = client.statements.get_derived_metrics_time_series(
        ciks=["AAPL", "MSFT"],
        statement_type="INCOME_STATEMENT",
        metrics=["GROSS_MARGIN"],
        frequency="annual",
    )

Filings

with ArcheClient(api_key="...") as client:
    page = client.filings.list("0000320193", filing_types=["10-K"], page=1, page_size=20)
    filing = client.filings.get("0000320193", "0000320193-24-000001")
    statements = client.filings.list_statements("0000320193", "0000320193-24-000001")

Statements

with ArcheClient(api_key="...") as client:
    versions = client.statements.list("0000320193", statement_type="INCOME_STATEMENT")
    timeline = client.statements.get_restatement_timeline(
        "0000320193", "INCOME_STATEMENT", 2024, "FY"
    )
    derived = client.statements.get_derived_metrics_time_series(
        ciks=["0000320193"],
        statement_type="INCOME_STATEMENT",
        metrics=["GROSS_MARGIN"],
        frequency="annual",
    )

    # As known at a date, only the statements asked for: here the FY2024
    # income statement. snapshot_hash still names the full as-of selection.
    as_of = client.statements.get_as_of_financials_page(
        "2025-03-31",
        "AAPL",
        limit=10,
        statement_type="INCOME_STATEMENT",
        fiscal_year_from=2024,
        fiscal_year_to=2024,
        fiscal_period="FY",
    )

Narratives

with ArcheClient(api_key="...") as client:
    narratives = client.narratives.list(
        "11111111-1111-1111-1111-111111111111",
        as_of="2024-12-31",
        narrative_type="CHANGE_SUMMARY",
    )

Bulk export

Scale and Enterprise plans can take a complete local copy of the served corpus as Parquet files instead of paging the API. sync() fetches only what changed:

with ArcheClient(api_key="...") as client:
    result = client.bulk.sync("./arche-corpus")

    print(result.snapshot_id, len(result.downloaded), "downloaded")
    print(len(result.skipped), "already held")

Download URLs are issued under the bulk-data license, which the organization accepts once per license version. Until it has, sync() raises BulkLicenseNotAcceptedError. Read the license and accept it from the SDK; the person named confirms they may bind the organization:

with ArcheClient(api_key="...") as client:
    current = client.bulk.license()
    print(current.license_version, current.accepted)
    if not current.accepted:
        print(current.text)
        client.bulk.accept_license(name="Jane Doe", email="jane@example.com")

accept_license() accepts the version and SHA-256 that license() returns, so the acceptance is of the text served at that moment. Accepting a version the organization already accepted returns the existing record unchanged.

Run it again tomorrow against the same directory and it transfers only the partitions whose bytes moved. A file is skipped when the local copy already hashes to the sha256 the snapshot's manifest records, so the skip is a statement about the bytes on disk rather than about a timestamp, and an interrupted sync resumes correctly. Digests are remembered in <destination>/.arche-bulk-sync.json so a second sync does not reread gigabytes to prove nothing changed; a file whose size or modification time differs from the record is rehashed rather than trusted, and rehash=True ignores the record entirely.

Restrict the sync, or watch it:

def show(event):
    print(f"[{event.index}/{event.total}] {event.action} {event.path}")

with ArcheClient(api_key="...") as client:
    client.bulk.sync("./arche-corpus", datasets=["statements", "financials"], progress=show)

Read the contract, browse snapshots, or fetch one file:

with ArcheClient(api_key="...") as client:
    for dataset in client.bulk.datasets():
        print(dataset.dataset, dataset.partition_column, [c.name for c in dataset.columns])

    manifest = client.bulk.snapshot()          # "latest" by default
    print(manifest.snapshot_id, manifest.read_at, manifest.bytes)

    changed = [item.path for item in manifest.files if item.changed]
    client.bulk.download_file(manifest.snapshot_id, changed[0], "./arche-corpus")

Every download is verified against the manifest's checksum and raises ChecksumMismatchError on a mismatch, removing the partial file. A manifest path that would write outside the destination is refused rather than resolved. The URLs are presigned and carry their own credentials: the SDK fetches them without an API key, and each one is charged its file's full size against the organization's daily download allowance when it is issued, not when the bytes move. Past the allowance the API answers RateLimitError with code BULK_DOWNLOAD_BUDGET_EXCEEDED.

Read the files with any Parquet reader. Partition directories are named fiscal_year_2025, not Hive's fiscal_year=2025, because the files already carry the partition as a column:

import duckdb

duckdb.sql("SELECT * FROM './arche-corpus/financials/*/*.parquet' LIMIT 5").show()

Agent tools

arche_sdk.tools.TOOLS defines four tools an agent can call: resolve a ticker, list a company's statements, read them as they were known on a past date (client.as_of.financials), and verify an earlier answer by its replay token (client.query.verify). Each has a name, a description and a Pydantic argument model, and tool.call(client, **arguments) returns JSON-ready data.

The same four tools ship for agent frameworks as langchain-arche, llama-index-tools-arche and crewai-arche, each exposing arche_tools(api_key=...).

Pagination

List endpoints return Page[T] with page, page_size, total, and items.

with ArcheClient(api_key="...") as client:
    first_page = client.filings.list("0000320193", page=1, page_size=50)
    if first_page.has_next:
        second_page = client.filings.list("0000320193", page=2, page_size=50)

    for filing in client.filings.iter_all("0000320193", page_size=100):
        print(filing.accession_id)

Error handling

from arche_sdk import ArcheClient
from arche_sdk.errors import APIError, RateLimitError

try:
    with ArcheClient(api_key="...") as client:
        client.companies.get("0000000000")
except RateLimitError as exc:
    print(exc.retry_after, exc.rate_limit_remaining)
except APIError as exc:
    print(exc.status_code, exc.code, exc.message, exc.trace_id, exc.request_id)

Request ID and trace ID

  • The SDK sends X-Request-ID on every request (auto-generated when missing).
  • On API errors, the SDK exposes:
    • request_id from response X-Request-ID
    • trace_id from canonical error envelope (error.trace_id)

License

Apache License 2.0. See LICENSE.

Metadata

Release files for arche-sdk 0.2.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 arche-sdk 0.2.0
File Size Uploaded Provenance Actions
arche_sdk-0.2.0.tar.gz 52.9 kB With provenance Details for arche_sdk-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for arche-sdk 0.2.0
File Interpreter ABI Platform Actions
arche_sdk-0.2.0-py3-none-any.whl Python 3 none any Details for arche_sdk-0.2.0-py3-none-any.whl

Total release size: 97.6 kB

Release files / arche_sdk-0.2.0.tar.gz

Download URL arche_sdk-0.2.0.tar.gz
Size 52.9 kB
Tags Source
SHA-256 checksum
How to use checksums
b54be63af448ec9ee1cc3d5fc0b63686645f10f8d177974ec8d40e9fb8a5a34a
BLAKE2b-256 checksum
How to use checksums
fc05410f7afe12fd754876dd546af4d326252834cfb1674eed10cd6e4beef664
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Oct 31, 2026.

Transparency log

Release files / arche_sdk-0.2.0-py3-none-any.whl

Download URL arche_sdk-0.2.0-py3-none-any.whl
Size 44.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
717fbb23c5a6b53e81708d5b8218c4a72a2690721b11d101c255d3b53bde9723
BLAKE2b-256 checksum
How to use checksums
b967621982217943370a1fd0b21bf6266f9c9d0f7aaf3f895423632bfcc48961
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 Oct 31, 2026.

Transparency log

Security for arche-sdk 0.2.0

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for arche_sdk-0.2.0.tar.gz

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 Oct 31, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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