Skip to main content

Official Python SDK for Celestin — zero-knowledge bank reconciliation API

Project description

celestin — Official Python SDK

Zero-knowledge bank reconciliation API — Python client library.

PyPI version Python License: MIT


Features

  • Full API coverage — Reconciliations and Tenants endpoints.
  • Zero-knowledge anonymisation — Client-side PII tokenisation with HKDF + HMAC-SHA256. Your raw data never reaches the server.
  • Automatic retries — Exponential backoff with jitter on 429 / 5xx. Honours Retry-After.
  • Typed error hierarchyisinstance-check on CelestinAuthError, CelestinValidationError, etc.
  • Idempotent POSTs — Auto-generated Idempotency-Key (UUID v4) on every POST.
  • Python 3.11+ — Uses native generics and from __future__ import annotations.

Installation

pip install celestin

With NER Layer 2 support (Phase 12+):

pip install "celestin[ner]"

Quickstart

import os
from celestin import Celestin

client = Celestin(
    api_key=os.environ["CELESTIN_API_KEY"],
    tenant_id="acme-sl",
)

# Submit a reconciliation job
job = client.reconciliations.create(body={
    "bank": [
        {"id": "b1", "date": "2026-03-01", "amount": -1200.50, "description": "PAGO PROVEEDOR"},
    ],
    "ledger": [
        {"id": "l1", "date": "2026-03-01", "debit": 0.0, "credit": 1200.50,
         "account": "400", "description": "Factura proveedor"},
    ],
})
print(f"Job id: {job['id']}, status: {job['status']}")

# Poll for completion
result = client.reconciliations.retrieve(job["id"])
print(f"Matches: {result['summary'].get('matches_total')}")

Zero-Knowledge Walkthrough

Celestin's anonymisation layer lets you run AI-powered reconciliation without sending plaintext PII (NIFs, IBANs, emails, phones, card numbers) to any external server.

How it works

  1. You call Anonymizer.redact() on every text field before building the request body.
  2. The SDK replaces each PII value with a deterministic opaque token such as <NIF:A3KM8P7ZNQWR5>.
  3. The server processes the tokenised data and returns results that also contain the tokens.
  4. You call Anonymizer.deanonymize() on any returned strings to recover the originals.

The token is computed as:

tenant_salt = HKDF-SHA256(master_key, tenant_id_utf8, "celestin-anon-v2", 32)
mac         = HMAC-SHA256(tenant_salt, normalised_value_utf8)
token       = "<TYPE:" + CrockfordBase32(mac[0:8]) + ">"

The master_key never leaves your process.

Code example

import os
from celestin import Celestin, Anonymizer

# 32-byte master key (keep secret, never log)
master_key = bytes.fromhex(os.environ["CELESTIN_MASTER_KEY"])

anon = Anonymizer(master_key=master_key, tenant_id="acme-sl")

raw_description = "Pago a 12345678Z IBAN ES9121000418450200051332"
safe = anon.redact(raw_description)
# safe -> "Pago a <NIF:...> IBAN <IBAN:...>"

client = Celestin(api_key=os.environ["CELESTIN_API_KEY"], tenant_id="acme-sl")
job = client.reconciliations.create(body={
    "bank": [{"id": "b1", "date": "2026-03-01", "amount": -1200.50,
              "description": safe}],
    "ledger": [...],
    "tokens": {
        "scheme": "hmac-sha256-base32-v2",
        "salt_fingerprint": anon.fingerprint(),
    },
})

# Recover original values in the returned match explanations
for match in job.get("matches", []):
    if "explanation" in match:
        match["explanation"] = anon.deanonymize(match["explanation"])

# Clean up when done with this reconciliation
anon.destroy()

Error Handling

from celestin import (
    Celestin,
    CelestinAuthError,
    CelestinValidationError,
    CelestinRateLimitError,
    CelestinConnectionError,
    CelestinError,
)
import time

client = Celestin(api_key="sk_test_...")

try:
    job = client.reconciliations.create(body={...})
except CelestinAuthError:
    # 401 — invalid or expired API key
    print("Check your CELESTIN_API_KEY environment variable.")
except CelestinValidationError as exc:
    # 422 — request body failed server-side validation
    for fe in exc.field_errors:
        print(f"  Field {fe['field']}: {fe['message']}")
except CelestinRateLimitError as exc:
    # 429 — rate limited
    wait = exc.retry_after_seconds or 60
    time.sleep(wait)
except CelestinConnectionError:
    # Network failure (all retries exhausted)
    print("Could not reach api.celestin.es — check your internet connection.")
except CelestinError as exc:
    # Catch-all for all Celestin errors
    print(f"Error {exc.code} (HTTP {exc.status}): {exc}")

Configuration

Parameter Type Default Description
api_key str required sk_test_... or sk_live_...
base_url str https://api.celestin.es Override for sandbox
tenant_id str None Default tenant for all requests
master_key str None Hex-encoded 32-byte key for anonymisation
timeout_ms int 30_000 Per-request timeout (milliseconds)
user_agent str None Appended to the SDK's User-Agent
client = Celestin(
    api_key="sk_test_...",
    base_url="https://sandbox-api.celestin.es",  # sandbox
    tenant_id="my-tenant",
    timeout_ms=10_000,
    user_agent="my-app/1.0",
)

Context manager

with Celestin(api_key="sk_test_...") as client:
    jobs = client.reconciliations.list()
# HTTP connection closed automatically

Resources

client.reconciliations

Method Description
create(body, *, tenant_id=None, idempotency_key=None, timeout_ms=None) Submit a new reconciliation job
retrieve(job_id, *, tenant_id=None, timeout_ms=None) Get a job by id
list(*, limit=None, cursor=None, status=None, tenant_id=None, timeout_ms=None) List jobs
cancel(job_id, *, tenant_id=None, timeout_ms=None) Cancel a queued/processing job

client.tenants

Method Description
create(body, *, timeout_ms=None) Create a tenant
retrieve(id, *, timeout_ms=None) Get a tenant by id or external_id
list(*, limit=None, cursor=None, timeout_ms=None) List tenants
update(id, body, *, timeout_ms=None) Partially update a tenant
soft_delete(id, *, timeout_ms=None) Soft-delete a tenant

SDK Parity

This SDK is byte-for-byte compatible with @celestin/sdk-node on the anonymisation tokenisation contract. A token emitted by this SDK for the triple (master_key, tenant_id, value) is identical to the token the Node SDK emits for the same triple. Phase 12 will ship a shared test-vector suite that pins this invariant across all official SDKs.


Development

# Clone and set up
git clone https://github.com/team-banzai/celestin
cd celestino/sdk-python
python -m venv .venv
.venv/bin/pip install -e ".[dev]"

# Run tests
.venv/bin/pytest tests/ -v

# Type check
.venv/bin/mypy --strict src/celestin/

License

MIT — see LICENSE.

Copyright (c) 2026 Team Banzai S.L.U.

Project details


Download files

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

Source Distribution

celestin-0.1.0a1.tar.gz (27.7 kB view details)

Uploaded Source

Built Distribution

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

celestin-0.1.0a1-py3-none-any.whl (31.4 kB view details)

Uploaded Python 3

File details

Details for the file celestin-0.1.0a1.tar.gz.

File metadata

  • Download URL: celestin-0.1.0a1.tar.gz
  • Upload date:
  • Size: 27.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for celestin-0.1.0a1.tar.gz
Algorithm Hash digest
SHA256 82bad193cc38c48c3e0dae26762f1c5642d4fbba889cada75e2370f95b52b4d1
MD5 842c30b9c62caa39c00e12ad1346ca13
BLAKE2b-256 494094b49f56ade01ad1f8e1cbc36d215ec7d6b862b9fd55ae0da1bdd9b5f59a

See more details on using hashes here.

File details

Details for the file celestin-0.1.0a1-py3-none-any.whl.

File metadata

  • Download URL: celestin-0.1.0a1-py3-none-any.whl
  • Upload date:
  • Size: 31.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for celestin-0.1.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 0c4dc1dbd2482f95ba83c892d0653adf5ee9133fdd1a73e0809e65d573cdcb32
MD5 97fd78acf793553c9daf7e30ff774b4c
BLAKE2b-256 0912535993697471482ae4336a9a3920a3794b5ae3cf2c94baa552014a8efd8a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page