Metadata-Version: 2.5
Name: fiscalrail
Version: 0.3.0
Summary: Official Python SDK for the FiscalRail API
Project-URL: Documentation, https://docs.fiscalrail.com/en/docs/python-sdk
Project-URL: Issues, https://github.com/fiscalrail/fiscalrail-python/issues
Project-URL: Source, https://github.com/fiscalrail/fiscalrail-python
Author-email: FiscalRail <hello@fiscalrail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: fiscalrail,invoicing,spain,tax,verifactu
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Office/Business :: Financial :: Accounting
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: requests<3,>=2.34
Description-Content-Type: text/markdown

# FiscalRail Python SDK

Typed Python client for issuing immutable invoices through FiscalRail.

[Documentation](https://docs.fiscalrail.com/en/docs/python-sdk) ·
[Changelog](https://github.com/fiscalrail/fiscalrail-python/blob/main/CHANGELOG.md)

```bash
python -m pip install fiscalrail
```

Pass a Test or Live secret explicitly when creating the client.

## Issue an invoice

```python
import os
from decimal import Decimal

from fiscalrail import FiscalRail
from fiscalrail.tax_regimes.es import irpf, vat

client = FiscalRail(os.environ["FISCALRAIL_API_KEY"])

invoice = client.invoices.issue(
    customer="cus_...",
    lines=[
        {
            "description": "Consulting services",
            "unit_price": Decimal("2500.00"),
            "taxes": [vat.general, irpf.professionals],
        }
    ],
)

pdf = client.invoice_pdfs.render_content(invoice.id, locale="en")
pdf.write_to_file(f"{invoice.code}.pdf")
```

The API key is required. Your application may read it from an environment
variable or secret manager, but the SDK never reads process configuration on
its own. The key selects the Test or Live account; the SDK has no separate
environment switch.

The client owns a pooled `requests.Session` by default. Applications that need
custom proxy, TLS, adapter or observability configuration can inject one:

```python
import os

import requests

from fiscalrail import FiscalRail

session = requests.Session()
client = FiscalRail(os.environ["FISCALRAIL_API_KEY"], session=session)
```

Injected sessions remain owned by the caller and are not closed by the SDK.

Invoice issuance automatically uses an idempotency key. Durable workflows can
provide and persist their own:

```python
invoice = client.invoices.issue(
    idempotency_key="a49b50f6-1571-4e06-a243-e258bda98e40",
    customer="cus_...",
    lines=[
        {
            "description": "Consulting services",
            "unit_price": "2500.00",
            "taxes": [vat.general],
        }
    ],
)
```

## Payment instructions

Create reusable payment instructions, optionally make them account defaults,
and set an invoice due date without sending bank details on every issuance:

```python
from datetime import date

instruction = client.payment_instructions.create(
    label="Main EUR account",
    type="bank_transfer",
    bank_transfer={
        "beneficiary": "Example supplier",
        "iban": "ES91 2100 0418 4502 0005 1332",
        "bic": "CAIXESBBXXX",
    },
)

client.accounts.update(
    "acct_...",
    default_payment_instructions=[instruction.id],
)

invoice = client.invoices.issue(
    payment_terms={"due_date": date(2026, 9, 30)},
    lines=[
        {
            "description": "Consulting services",
            "unit_price": "2500.00",
            "taxes": [vat.general],
        }
    ],
)
```

Pass `payment_terms={"options": [instruction.id]}` to override the account
defaults for a specific invoice. Pass an empty `options` list to render no
payment instructions.

## Typed request values

Calls are type checked directly. Exported `TypedDict` definitions also make
larger payloads reusable without introducing runtime parameter wrappers:

```python
from fiscalrail.params import InvoiceIssueParams

params = InvoiceIssueParams(
    customer="cus_...",
    lines=[
        {
            "description": "Consulting services",
            "unit_price": Decimal("2500.00"),
            "taxes": [vat.general, irpf.professionals],
        }
    ],
)

invoice = client.invoices.issue(**params)
```

Responses are dependency-free frozen dataclasses. Dates, timestamps and monetary
amounts are parsed into `date`, `datetime` and `Decimal` values. Unknown response
fields are retained in `response.extra_fields` for forward compatibility and
remain available through attribute access.

The response dataclasses, request `TypedDict`s, enums and operation registry are
generated from FiscalRail's OpenAPI contract. The public client and resource
methods remain hand-written so they can expose domain verbs, pooling,
idempotency and retry behavior instead of generator-shaped HTTP calls.

## Resources

- `client.accounts`
- `client.api_keys`
- `client.customers`
- `client.event_destinations`
- `client.events`
- `client.invoice_series`
- `client.invoices`
- `client.invoice_pdfs`
- `client.payment_instructions`
- `client.tax_ids`
- `client.tax_regimes`

Invoices use the domain verbs `issue` and `amend`; they are never updated.
Account resources expose list, retrieve, and update operations. Customer and
series and payment-instruction resources expose ordinary create, retrieve,
update, list and delete operations.

## Verify webhooks

Verify the exact request body before parsing or processing it:

```python
from fiscalrail.webhooks import construct_event

event = construct_event(raw_body, signature_header, signing_secret)
```

`construct_event` checks the HMAC in constant time, applies a five-minute
timestamp tolerance, and raises `WebhookSignatureError` when verification
fails.

## Development

```bash
uv sync --all-groups
uv run python scripts/generate_contract.py
uv run python scripts/generate_contract.py --check
uv run pytest
uv run ty check
uv run ruff check .
uv build
```

Release maintainers should follow the
[release guide](https://github.com/fiscalrail/fiscalrail-python/blob/main/RELEASING.md).
