nodda-client (Python)
Cliente oficial de la API de Nodda para emitir y consultar facturas VERI*FACTU de la Agencia Tributaria (AEAT) desde tu propio programa (ERP, tienda online, TPV…).
Nodda se encarga de la firma con tu certificado, del XML, de la cadena de huellas y del envío a la AEAT: tú solo mandas los datos de la factura en JSON.
Instalación
pip install nodda-client
Requisitos: Python 3.8 o superior. Sin dependencias (solo la librería estándar).
Antes de empezar
- Crea tu cuenta en el portal de Nodda y da de alta tu empresa (NIF y certificado digital).
- Genera tu clave API en el portal → API keys.
- Usa la dirección del entorno con su clave:
| Entorno | Dirección | Uso |
|---|---|---|
| Pruebas | https://sandbox.nodda.es |
Envía al entorno de pruebas de la AEAT, sin validez fiscal |
| Producción | https://api.nodda.es |
Facturas reales |
La clave de pruebas no sirve en producción, ni al revés.
Uso
import os
from nodda_client import NoddaClient
nodda = NoddaClient("https://sandbox.nodda.es", os.environ["NODDA_API_KEY"])
r = nodda.crear_factura({
"series": "2026", "number": "0001", "issueDate": "2026-11-03", "invoiceType": "F1",
"description": "Servicios de consultoría", "taxRegimeKey": "01", "operationQualification": "S1",
"taxBase": "100.00", "taxRate": "21", "taxAmount": "21.00", "totalAmount": "121.00",
"recipients": [{"nif": "B12345674", "name": "Cliente Demo SL"}],
})
# r["status"] == "queued": la API responde al momento; la AEAT, unos segundos después.
estado = nodda.consultar_estado(r["id"]) # queued, sent, accepted_with_errors o permanently_failed
number es el número de la factura dentro de su serie (sin huecos ni repeticiones). Puedes omitirlo si la serie tiene numeración automática configurada (en el portal, Empresas → series de numeración, o con PUT /v1/emisores/{id}/series); si no, la API responde series_not_configured.
Si tu clave da acceso a varias empresas (NIF), indica cuál en el parámetro nif de cada método. Puedes asociar la factura a un centro de coste enviando costCenterId en los datos.
Métodos
| Método | Endpoint |
|---|---|
crear_factura(datos, nif=None) |
POST /v1/invoices |
consultar_estado(id, nif=None) |
GET /v1/invoices/{id} |
listar_facturas(filtros=None, nif=None) |
GET /v1/invoices |
cancelar_factura(id, datos=None, nif=None) |
POST /v1/invoices/{id}/cancel |
reintentar_factura(id, tipo=None, nif=None) |
POST /v1/invoices/{id}/retry |
obtener_url_qr(id) / obtener_imagen_qr(id) |
GET /v1/invoices/{id}/qr |
estado_sistema(nif=None) |
GET /v1/status |
obtener_perfil() |
GET /v1/client |
configurar_webhook(url, nif=None) / quitar_webhook(nif=None) |
PUT / DELETE /v1/webhooks |
NoddaClient.verificar_firma_webhook(cuerpo, firma, secreto) |
Comprueba la firma de un aviso |
Avisos (webhooks)
En lugar de consultar el estado de cada factura, Nodda puede avisar a tu servidor cuando la AEAT responde. Configura la URL con configurar_webhook(url) (la respuesta trae el secreto una sola vez: guárdalo) y, en tu endpoint, comprueba la firma antes de confiar en el aviso:
# cuerpo: bytes tal cual llegan; firma: cabecera X-Nodda-Signature
if not NoddaClient.verificar_firma_webhook(cuerpo, firma, os.environ["NODDA_WEBHOOK_SECRET"]):
return 401
El cuerpo trae id (número de factura), status (sent, accepted_with_errors o permanently_failed), razon, eventId y los datos del acuse de la AEAT. Responde con un código 2xx; si no, Nodda lo reintenta.
Errores
Si la API responde con un error, se lanza NoddaApiException con el código HTTP y un código estable (por ejemplo invalid_request, business_rule_violation, certificate_not_configured). Si no hubo respuesta (fallo de red), se lanza NoddaException: puedes reintentar la misma petición.
Documentación
Guía completa, campos de cada petición y códigos de error: https://app.nodda.es/developers/introduccion Referencia OpenAPI: https://api.nodda.es/openapi.json
Soporte: soporte@nodda.es
Licencia
MIT
Metadata
Release files for nodda-client 1.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| nodda_client-1.2.1.tar.gz | 12.9 kB | Without provenance | Details for nodda_client-1.2.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| nodda_client-1.2.1-py3-none-any.whl | Python 3 | none | any | Details for nodda_client-1.2.1-py3-none-any.whl |
Total release size: 23.1 kB
Release files / nodda_client-1.2.1.tar.gz
| Download URL | nodda_client-1.2.1.tar.gz |
|---|---|
| Size | 12.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8eedbeeab149683eb19e3eaf4389b2b242a21a1d3564ea9afe884b1269c51489
|
|
BLAKE2b-256 checksum How to use checksums |
f049cb3a1e8596bd9af771524fc31ca0f34d0f34c1f6c853b753e976b40fd2ed
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.12.16
|
Release files / nodda_client-1.2.1-py3-none-any.whl
| Download URL | nodda_client-1.2.1-py3-none-any.whl |
|---|---|
| Size | 10.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0a29ad05ab130c1a8188113ecbd6ead4796710fd7d9ec9c45e7e4afc7873df52
|
|
BLAKE2b-256 checksum How to use checksums |
63bb12599c872673a2da4df3532719ac78b47367e1c0928748c28f80cc812524
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.12.16
|
Security for nodda-client 1.2.1
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.