Skip to main content

SpreadSpace Python SDK

Official Python client for the SpreadSpace API — document extraction and financial spreading for lending.

Some examples below require the generated core (built in CI) or a live sandbox key. They are marked [needs sandbox key] / [needs generated core].

Install

pip install spreadspace

Requires Python 3.9+.

Authentication

from spreadspace import SpreadSpace

client = SpreadSpace(api_key="ss_test_...")   # or omit and set SPREADSPACE_API_KEY

The key prefix selects the environment:

  • ss_test_... — routes to your sandbox tenant (seed data, safe to experiment).
  • ss_live_... — routes to your live tenant (real data).

If api_key is omitted, the client reads SPREADSPACE_API_KEY from the environment. Never hard-code a live key; never commit any key.

Client options

client = SpreadSpace(
    api_key="ss_test_...",
    base_url="https://api.spreadspace.app",   # override for a private deployment
    api_version="2026-05-03",                # pins the SpreadSpace-Version header
    timeout=60.0,                            # seconds, per request
    max_retries=2,                           # 429 + 5xx + transport errors
)

API version pinning

Every request sends a dated SpreadSpace-Version header. The SDK pins a default version per release (decoupled from the SDK's own semver). Pin it explicitly to insulate your integration from server-side changes, and override per call when you need a newer surface:

client.borrowers.list(api_version="2026-06-01")   # one call on a newer version

Pagination (lazy, auto cursor)

List endpoints return a lazy iterator that walks cursors for you — it fetches the next page only as you consume it.

for borrower in client.borrowers.list():
    print(borrower["id"])

# Filters pass straight through and persist across pages:
for job in client.jobs.list(status="completed", limit=50):
    print(job["id"])

Extraction export + wait

Exports run asynchronously. create returns a handle; wait polls to completion (raising ExportFailedError on failed, ExportTimeoutError on timeout). Terminal statuses are succeeded / failed / cancelled; cancelling — a cancel that landed mid-bundle — is NOT terminal, so wait polls through it. format is json, csv, or xlsx; xlsx is available for bank statements only.

borrower_id, loan_id and document_ids are required, as they are on the server.

export = client.exports.create(
    borrower_id="abc123",
    loan_id="def456",
    document_ids=["doc_1f2e3d4c5b6a7908", "doc_2a3b4c5d6e7f8091"],
    format="json",
)
result = export.wait(timeout=300)   # seconds
print(result.status, result.download_url)   # link minted fresh on every read
print(result.document_counts)               # {"requested": .., "exported": .., "skipped": ..}
print(result.bundle)                        # {"name": .., "size_bytes": .., "line_item_count": ..}

# Or ask for a fresh link by id (raises ExportNotReadyError until succeeded).
# The expiry comes off the same read, so it describes this link:
link = client.exports.download_link(result.export_id)
print(link.url, link.expires_at)

# List exports as ExtractionExport rows (items live under `exports`, not `data`):
for row in client.exports.list(status="running"):
    print(row.export_id, row.status)

# Cancel a still-running export (cancelling a finished one raises ConflictError;
# cancelling an already-cancelled one is an idempotent success):
export.cancel()
# ...or by id: client.exports.cancel(result.export_id)

Upload a document + wait for processing

job = client.documents.upload("statement.pdf", loan_id="def456", borrower_id="abc123")
final = job.wait(timeout=600)   # seconds
print(final["status"])

The upload helper requests a presigned URL, PUTs the file bytes directly to storage with the matching Content-Type (part of the V4 signature), then returns a job handle you can wait on. Every upload belongs to a loan, so loan_id is required; borrower_id is optional.

Error handling

All errors derive from SpreadSpaceError. Match on the typed subclass, never on the message string:

from spreadspace import (
    SpreadSpaceError,       # base
    NetworkError,           # transport failure, no HTTP response
    BadRequestError,        # 400
    AuthenticationError,    # 401
    PermissionDeniedError,  # 403
    NotFoundError,          # 404
    ConflictError,          # 409
    RateLimitError,         # 429
    InternalServerError,    # 5xx
)

try:
    client.borrowers.get("missing-id")
except RateLimitError as e:
    print("retry after", e.retry_after, "seconds")
except NotFoundError as e:
    print("not found")
except SpreadSpaceError as e:
    # Every error carries request_id — quote it in support tickets.
    print(e.message, e.status_code, e.request_id)

request_id comes from the X-Request-ID response header (falling back to the error body). Transient failures (429, 5xx, transport errors) are retried automatically up to max_retries with exponential backoff + full jitter, honoring Retry-After.

Money is exact

Monetary values decode as decimal.Decimal, not float — the SDK reads the literal digits off the wire, so amounts are exact with no float rounding:

b = client.borrowers.get("...")          # [needs sandbox key]
assert b["total_revenue"] == Decimal("1234.56")   # never 1234.5600000000001

Development

The generated OpenAPI core lives in src/spreadspace/_generated/ and is built in CI (scripts/generate.sh, Java-based — not run locally). It is gitignored and must never be hand-edited. The hand-written ergonomic layer (transport, helpers, typed errors) is the only code committed by hand.

pip install -e '.[dev]'
pytest

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spreadspace-0.3.0.tar.gz (57.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

spreadspace-0.3.0-py3-none-any.whl (39.1 kB view details)

Uploaded Python 3

File details

Details for the file spreadspace-0.3.0.tar.gz.

File metadata

  • Download URL: spreadspace-0.3.0.tar.gz
  • Upload date:
  • Size: 57.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for spreadspace-0.3.0.tar.gz
Algorithm Hash digest
SHA256 6264dfe670a4107f6c4d78185be5d34006c9ca048c78eaa807ec443b2ee14f6d
MD5 6778483dd39dc3aee889396e9def72fc
BLAKE2b-256 11be21a026ed60e47c3dfa08f69aa84e77870c454b491de8a1cc571936fb5ddf

See more details on using hashes here.

Provenance

The following attestation bundles were made for spreadspace-0.3.0.tar.gz:

Publisher: sdk.yml on DocDissect/DocDissectOfficial

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spreadspace-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: spreadspace-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 39.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for spreadspace-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 16c9b3d56f514e717c6efb7e1b14dad0880a41df518d974ae66a09d5cbcfe50d
MD5 30eded5cf3fdffb3a52fffb351df3202
BLAKE2b-256 a8f013307649b1f8321740c01a0b3797d7e6b154d7129d1daabbac98c25c5649

See more details on using hashes here.

Provenance

The following attestation bundles were made for spreadspace-0.3.0-py3-none-any.whl:

Publisher: sdk.yml on DocDissect/DocDissectOfficial

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.4.0

2 files

This release

0.3.0 This release

2 files

0.1.8

2 files

0.1.6

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 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