Metadata-Version: 2.4
Name: ecuafact
Version: 1.0.0b1
Summary: Cliente oficial en Python del API publico de facturacion electronica Ecuafact (contrato v1).
Author: Ecuanexus
License-Expression: MIT
Project-URL: Documentation, https://docsapi.ecuafact.com/v1/guias/sdk-python
Project-URL: Homepage, https://docsapi.ecuafact.com/v1/guias/sdk-python
Keywords: ecuafact,sri,facturacion-electronica,ecuador,api,sdk
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic>=2.6
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Dynamic: license-file

# ecuafact (Python)

Cliente oficial en Python del API publico de facturacion electronica Ecuafact (contrato v1). Cubre
autenticacion, idempotencia, reintentos y firma de webhooks. Requiere Python 3.9+.

## Instalacion

```bash
pip install ecuafact
```

## Uso

```python
import os
from ecuafact import ComprobanteRequest, EcuafactClient, EcuafactClientOptions, InfoTributaria

client = EcuafactClient(EcuafactClientOptions(
    base_address="https://staging-api.mynexusapi.com/",  # sandbox; produccion: https://api.mynexusapi.com/
    api_key=os.environ["ECUAFACT_API_KEY"],
    identificacion="1790012345001",  # solo integraciones de un RUC
))

resultado = client.emitir(ComprobanteRequest(
    origen_referencia="MiERP",
    referencia_externa="FACTURA-2026-0001",
    info_tributaria=InfoTributaria(
        ruc="1790012345001", cod_doc="01", estab="002", pto_emi="001", secuencial="000000123"
    ),
    # info=..., detalles=...
))
print(resultado.admission.id_operacion, resultado.admission.codigo)
```

### Multi-RUC

```python
ruc = client.para("1790099987001")
pagina = ruc.listar_emitidos()
```

## Idempotencia

`idempotency_key` es opcional: si no se envia, el SDK la genera, la reutiliza en los reintentos y la
devuelve en `resultado.idempotency_key` (y en el error, como `EcuafactApiException.idempotency_key`).
Al reintentar a nivel de aplicacion **reutiliza la clave devuelta**. La correlacion de la respuesta
queda en `resultado.correlation_id` (o `EcuafactApiException.id_seguimiento` en error).

Los fallos transitorios (`408/425/429/5xx`) se reintentan con la misma clave respetando `Retry-After`;
el resto de los 4xx no.

## Opciones

| Opcion | Default | Descripcion |
|---|---|---|
| `base_address` | — | Direccion base del API (obligatoria) |
| `api_key` | — | Credencial `X-Api-Key` (obligatoria) |
| `identificacion` | `None` | RUC por defecto (opcional) |
| `timeout` | `100.0` | Tiempo maximo por intento (segundos) |
| `user_agent` | `Ecuafact.Sdk/1.0` | User-Agent |
| `retry_transient_failures` | `True` | Reintenta `408/425/429/5xx` |
| `max_attempts` | `3` | Intentos por solicitud |
| `respect_retry_after` | `True` | Respeta `Retry-After` en `429`/`503` |
| `max_retry_delay_ms` | `60000` | Espera maxima entre reintentos |

## Errores

Los errores del API se lanzan como `EcuafactApiException` (`codigo`, `mensaje`, `estado_http`,
`id_seguimiento`, `errores`, `idempotency_key`). Los errores locales de configuracion o transporte son
`EcuafactSdkException`.

## Webhooks

```python
from ecuafact import verify

valido = verify(secreto, cabecera, cuerpo_crudo, tolerance_seconds=300)
```

## Documentacion

- [Guia del SDK Python](https://docsapi.ecuafact.com/v1/guias/sdk-python)

## Licencia

MIT.
