Skip to main content

billos (Python)

BillOS from Python: legally valid Israeli tax documents (חשבונית מס, קבלה, זיכוי), the expense ledger, webhooks and the regulatory outputs, over one small client with no dependencies beyond the standard library (Python 3.9+).

pip install billos
from billos import BillOS, BillOSError

billos = BillOS(api_key=os.environ["BILLOS_API_KEY"])
bid = billos.businesses.list()["businesses"][0]["id"]

created = billos.documents.create(bid, {
    "docType": 320,
    "priceMode": "gross",
    "party": {"name": "דנה לוי", "phone": "0521111111"},
    "lines": [{"description": "איפור כלה", "quantity": 1, "unitPriceExVat": 120000}],
    "payments": [{"method": "card", "amount": 120000}],
}, idempotency_key="order-8812")

issued = billos.documents.issue(bid, created["document"]["id"])
print(issued["document"]["docNumber"])

pdf = billos.documents.print(bid, created["document"]["id"])   # Binary: .bytes, .content_type, .variant
link = billos.documents.share(bid, created["document"]["id"])   # a public URL for the customer

Money is integer agorot everywhere, exactly like the API (₪354.00 is 35400); a foreign-currency document ("currency": "USD") is in that currency's cents. Nothing in the client converts.

What you get

  • Every operation in the spec as namespace.method (snake_case): businesses, parties, documents, recurring, legacy, expenses, exports, files, webhooks, events, keys, usage, requests, sandbox, and for Connect and shared access access, connections, apps. OPERATIONS (method and path per operation) is generated from the OpenAPI spec, and a test checks every operation has a method, so the client cannot lag behind the API.
  • The conventions handled: X-Api-Key, the {ok, ...} envelope returned as a dict (plus request_id), Idempotency-Key from idempotency_key=, Retry-After honoured.
  • api_version="2026-09-08" pins a dated API version (sent as BillOS-Version); the default is the current one.
  • Retries on 429 / 502 / 503 / 504 and network errors, up to max_retries (default 2), for GET/DELETE and for POSTs carrying an idempotency key; never for a POST without one.
  • BillOSError with status, reason, request_id, body, retryable. Branch on reason.
  • Binary answers (documents.preview, documents.print, files.get, a PDF report) come back as Binary(bytes, content_type, variant, request_id).
  • verify_webhook_signature(secret, header, raw_body) for the X-BillOS-Signature header.
  • access_token="bkat_…" instead of api_key= acts for one business whose owner connected your app (Connect).
  • A bk_test_ key answers from the sandbox with no change on your side (billos.sandbox.seed() fills it with demo data).

Documentation and the OpenAPI spec: https://docs.billos.co.il. MIT.

Connect: acting for someone else's business

An API key holds the businesses you opened. A Connect token holds one business whose owner connected your app (OAuth 2.0 with PKCE, guide: https://docs.billos.co.il/connect):

merchant = BillOS(access_token=token)                # bkat_…, one business, the granted scopes
merchant.documents.list(business_id)

dev = BillOS(api_key=key)                            # your key sees connected businesses too
dev.apps.create({"name": "My App", "redirectUris": ["https://app.example/cb"], "scopes": ["documents:read"]})
dev.connections.list(business_id)                    # what an owner connected, and the way out
dev.access.invite(business_id, {"email": "rina@example.com", "role": "accountant"})

Ask for a sandbox key, and check before the permanent act

from billos import BillOS, BillOSError, create_sandbox, wait_for_sandbox

pending = create_sandbox(name="my app")         # no credentials
print("Open", pending["verifyUrl"], "and approve")   # show it to the person; only a person can
box = wait_for_sandbox(pending)                  # returns once they approve, raises on expiry
billos = BillOS(api_key=box["apiKey"])

try:
    billos.documents.validate(business_id, draft_id)   # every check issue runs, no number taken
    billos.documents.issue(business_id, draft_id)
except BillOSError as e:
    # e.reason "payments_mismatch", e.param "payments", e.hint "The payments add up to 30000…",
    # e.doc_url, e.request_id, and e.retryable: whether the SAME request can succeed if sent again
    raise

What is new in 0.5.0

  • create_sandbox() and wait_for_sandbox(): ask for a sandbox key with no credentials (POST /sandboxes), show the person the link, and collect the key once they approve.
  • documents.validate: a dry run of issue. Nothing is numbered.
  • Errors teach: BillOSError carries hint, param and doc_url, and retryable is the API's own answer when it gives one.

What is new in 0.3.0

  • Connect: access_token= for a per-business token, and the apps namespace to register and manage the app behind it (create, list, get, update, rotate_secret, delete).
  • Shared access: access.list / access.invite / access.revoke open a business to a person by email and role (accountant, bookkeeper, viewer), and connections.list / connections.revoke are the owner's view of the apps connected to it.
  • Fine scopes: a refusal names the half it needed (missing scope: documents:write). A key's coarse scope covers both halves, so nothing you hold changes.

Metadata

Release files for billos 0.5.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 billos 0.5.0
File Size Uploaded Provenance Actions
billos-0.5.0.tar.gz 19.5 kB Without provenance Details for billos-0.5.0.tar.gz

Built distribution (wheel)

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

Total release size: 34.8 kB

Release files / billos-0.5.0.tar.gz

Download URL billos-0.5.0.tar.gz
Size 19.5 kB
Tags Source
SHA-256 checksum
How to use checksums
58df478e0e734b31264ae3302ab14ce403646c7acd5c496e42f70219dce5db0e
BLAKE2b-256 checksum
How to use checksums
2dfe71be1db11c6736a1e109d81da6994e5acdf5f10f1ac0c08ee0e39f78890f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / billos-0.5.0-py3-none-any.whl

Download URL billos-0.5.0-py3-none-any.whl
Size 15.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
da86ae5940ebdc6b3742831c32c9328aadf7c244197144bf8cc149ef4a0a75ec
BLAKE2b-256 checksum
How to use checksums
1627b773ffb4f242d14779d38b1d205e40c2772b00c82fae1484f5cdaad18c61
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Security for billos 0.5.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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

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