FiscalRail Python SDK
Typed Python client for issuing immutable invoices through FiscalRail.
python -m pip install fiscalrail
Pass a Test or Live secret explicitly when creating the client.
Issue an invoice
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:
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:
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:
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.account_invoicing.update(
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:
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 TypedDicts, 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.accountsclient.account_invoicingclient.account_tax_regimesclient.api_keysclient.balancesclient.customersclient.event_destinationsclient.eventsclient.invoice_seriesclient.invoicesclient.invoice_pdfsclient.payment_instructionsclient.tax_idsclient.tax_regimes
Invoices use the domain verbs issue and amend; they are never updated.
The current account and its invoicing settings each expose retrieve and update. Customer and
series and payment-instruction resources expose ordinary create, retrieve,
update, list and delete operations.
Account balance and tax-regime state
balance = client.balances.retrieve()
print(balance.amount) # Decimal, including zero or negative balances
regime = client.account_tax_regimes.retrieve()
if regime.key == "es" and regime.es.representation is not None:
print(regime.es.representation.status)
Balances exist only for Live accounts; retrieving a Test account's balance
raises ResourceNotFoundError. The amount is informational: paid operations
can still fail with BalanceExhaustedError if the balance changes.
Account tax regimes return a GlobalAccountTaxRegime or
SpanishAccountTaxRegime. Spanish Test accounts have es.representation=None;
unverified Live representation timestamps can also be None. Both resources
retain request_id, preserve unknown fields, and use the client's safe-read
retry behavior. client.tax_regimes continues to expose the general tax
catalog; client.account_tax_regimes exposes account-specific state.
Verify webhooks
Verify the exact request body before parsing or processing it:
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
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.
Metadata
Release files for fiscalrail 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fiscalrail-0.5.0.tar.gz | 88.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fiscalrail-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 118.7 kB
Release files / fiscalrail-0.5.0.tar.gz
| Download URL | fiscalrail-0.5.0.tar.gz |
|---|---|
| Size | 88.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3a8e748425bfa801aa2d37bcc455d9ecabd4fd60ea0903bfb84af4d7ee645e35
|
|
BLAKE2b-256 checksum How to use checksums |
aa56c552c729deb16575bbb4afe6c73e6e3e47ab99df7004d82e2fa2a67a79f9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency logRelease files / fiscalrail-0.5.0-py3-none-any.whl
| Download URL | fiscalrail-0.5.0-py3-none-any.whl |
|---|---|
| Size | 30.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
87f323bfff0a68ff4a3c14f1a391cdaf82beb531d4a91b318e44d5bcc2ba80c4
|
|
BLAKE2b-256 checksum How to use checksums |
150323a88ffaa0e3978595062cad132cf43aff905b9038ba9b5220a8400b0342
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency log