# SDK de Python

Instala el paquete fiscalrail y usa su cliente tipado con conexiones reutilizables.

El paquete oficial `fiscalrail` es la forma recomendada de llamar a FiscalRail desde Python. Incluye parámetros tipados, dataclasses inmutables para las respuestas, conexiones reutilizables, reintentos seguros y helpers fiscales por país, sin añadir un framework de validación en tiempo de ejecución.

## Instala y autentica

```bash
python -m pip install fiscalrail
export FISCALRAIL_API_KEY=ak_test_...
```

Crea un cliente y reutilízalo durante toda la vida del proceso de tu aplicación:

```python
import os

from fiscalrail import FiscalRail

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

La clave de API es un argumento obligatorio del constructor. Tu aplicación decide si procede de una variable de entorno, de un gestor de secretos o de otra fuente de configuración; el SDK no inspecciona las variables del proceso. Test y Live usan la misma URL base y la clave selecciona el entorno de la cuenta.

`FiscalRail` mantiene internamente una `requests.Session`. Úsalo como gestor de contexto en scripts breves o llama a `client.close()` al cerrar la aplicación. Puedes inyectar tu propia `requests.Session` si necesitas proxies, configuración TLS, adapters u observabilidad; en ese caso la sesión sigue siendo propiedad de tu aplicación.

## Emite una factura

Usa `Decimal` para importes y los helpers de España para impuestos definidos en el catálogo:

```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": "Servicios de consultoría",
            "unit_price": Decimal("2500.00"),
            "taxes": [vat.general, irpf.professionals],
        }
    ],
)

print(invoice.code)
print(invoice.totals.payable)
```

La emisión y la rectificación generan automáticamente una clave de idempotencia. Los trabajos duraderos deberían proporcionar y guardar su propio `idempotency_key`, de modo que un reintento después de reiniciar el proceso identifique la misma operación.

## Peticiones y respuestas tipadas

Los métodos aceptan argumentos con nombre y tipados. Los `TypedDict` exportados son útiles cuando construyes el payload antes de hacer la llamada:

```python
from decimal import Decimal

from fiscalrail.params import InvoiceIssueParams
from fiscalrail.tax_regimes.es import vat

params = InvoiceIssueParams(
    customer="cus_...",
    lines=[
        {
            "description": "Servicios de consultoría",
            "unit_price": Decimal("2500.00"),
            "taxes": [vat.general],
        }
    ],
)

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

Las respuestas son dataclasses congelados generados desde el contrato OpenAPI de FiscalRail. Las fechas se convierten en `date`, las marcas de tiempo en `datetime` y los decimales en `Decimal`. Los campos de respuesta desconocidos permanecen disponibles en `response.extra_fields`, por lo que añadir un campo no rompe versiones anteriores del SDK.

## Reintentos y errores

El cliente reintenta errores de conexión, timeouts y respuestas `408`, `429` y `5xx` transitorias solo cuando la operación se puede repetir de forma segura. Respeta `Retry-After` y, en los demás casos, aplica un backoff exponencial limitado. De forma predeterminada hace dos reintentos; usa `max_retries=0` para desactivarlos.

Los errores de FiscalRail se lanzan como subclases de `FiscalRailError`. Los errores de API exponen `status_code`, `code`, `request_id` y los detalles de validación cuando existan. Los errores de conexión y timeout conservan la clave de idempotencia para que un worker duradero pueda decidir cómo continuar.

## Recursos disponibles

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

Las facturas usan los verbos de dominio `issue` y `amend`; los documentos emitidos nunca se actualizan. Cada operación de la [referencia de la API](/en/api/introduction) tiene un método correspondiente en el SDK.

## Verifica webhooks

Pasa el cuerpo original de la petición, la cabecera `FiscalRail-Signature` y el secreto de firma del destino a `construct_event`:

```python
from fiscalrail.webhooks import construct_event

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

El helper verifica el HMAC en tiempo constante, rechaza marcas de tiempo con más de cinco minutos y solo entonces interpreta el evento JSON. Una verificación fallida lanza `WebhookSignatureError`.
