Metadata-Version: 2.4
Name: billos
Version: 0.2.0
Summary: BillOS for Python: Israeli tax documents, expenses, webhooks and the regulatory outputs, over one small client.
Author: BillOS
License-Expression: MIT
Project-URL: Documentation, https://docs.billos.co.il
Project-URL: Homepage, https://billos.co.il
Project-URL: Source, https://github.com/baraviz/pest-os/tree/main/packages/billos-python
Keywords: billos,invoice,bookkeeping,israel,tax,api
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Classifier: Topic :: Office/Business :: Financial :: Accounting
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# 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+).

```bash
pip install billos
```

```python
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`. `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.
- 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.

## What is new in 0.2.0

Twelve operations the API grew since 0.1.0, and one argument:

- **Open items**: `documents.receivables`, `documents.add_settlement`, `documents.remove_settlement`, and `settles` / `dueDate` on a draft.
- **Partial credit**: `documents.credit_note(bid, id, {"amount": ..., "reason": ...})`.
- **The VAT return**: `exports.pcn874` writes the PCN874.TXT, `exports.vat` answers the figures and warnings without a file.
- **Your own traffic**: `requests.list` (the 7-day request log) and `latency` on `usage.get`.
- **Webhook replay**: `webhooks.replay(id, {"from": ..., "to": ...})`.
- **The archive**: the `legacy` namespace, for documents from the software a business used before BillOS.
- **`api_version=`** pins a dated API version on every call.
