Saltearse al contenido

Empezar

Buenas prácticas

No bloquees la venta esperando a la administración

Sección titulada «No bloquees la venta esperando a la administración»

Es el error más caro, sobre todo en Ecuador: el SRI es un servicio externo que normalmente tarda segundos, pero que un día tarda minutos o no responde. Si tu caja espera a la autorización para cerrar la venta, ese día no vendes.

En España el problema no existe —la factura es válida en cuanto la API responde— pero la costumbre de no bloquear sigue siendo buena.

# Mal: el usuario mira una pantalla de carga hasta que el SRI conteste.
factura = emitir(venta)
esperar_autorizacion(factura["id"]) # Puede tardar minutos.
mostrar_ticket(factura)
# Bien: la venta se cierra con el 202; la autorización llega después.
factura = emitir(venta)
venta.factura_id = factura["id"]
venta.clave_acceso = factura["clave_acceso"]
venta.save()
cerrar_venta(venta) # El cliente se va con su ticket.
encolar_seguimiento(factura["id"]) # Un proceso de fondo sigue el estado.

El cliente recibe su factura por correo en cuanto se autorice, sin haber esperado.

Por cada factura, en tu base de datos:

DatoPara qué
idConsultar, descargar y reenviar por la API
clave_acceso (Ecuador) o huella (España)Identificar el comprobante ante la administración
secuencialEl número de la factura
ambienteSaber si fue de pruebas o real cuando alguien pregunte meses después

Y el request_id de la emisión, en tu registro: es lo primero que pedirá soporte.

Las dos, siempre. Protegen cosas distintas:

respuesta = client.post(
"/invoices/issue",
json={"referencia_externa": venta.codigo, ...}, # Protege la venta.
headers={"Idempotency-Key": f"venta-{venta.id}"}, # Protege la petición.
)

Y trata el conflicto como éxito, no como error:

if error["code"] == "external_id_conflict":
# La venta ya estaba facturada; recupera la factura en vez de fallar.
return client.get(f"/invoices/{error['details']['id']}").json()

Ver Idempotencia.

REINTENTABLES = {"rate_limited", "internal_error", "idempotency_in_progress"}

Esos merecen otro intento, con espera creciente y respetando Retry-After. Un validation_error o un totals_mismatch no: reintentarlos da el mismo resultado y gasta cuota.

Valida las identificaciones antes de facturar

Sección titulada «Valida las identificaciones antes de facturar»

El rechazo por identificación del comprador es de los más frecuentes, y casi siempre viene de un RUC, una cédula o un NIF mal tecleados. Validar el dígito o la letra de control en tu formulario evita el rechazo —y la llamada del cliente preguntando por su factura.

En España, además, guarda el país de cada cliente: sin él no se puede facturar a nadie con una identificación que no sea española.

No compartas una clave entre tu ERP, tu tienda y tu app. Con una clave por sistema:

  • Los límites de peticiones no se pisan entre ellos.
  • El registro dice quién hizo cada llamada.
  • Si una se filtra, revocas solo esa.
  • Cada una lleva los permisos que de verdad necesita.

Un sistema que solo emite no necesita invoices:read. Uno que solo consulta no necesita invoices:write. Si la clave se filtra, el daño es el que permitan sus scopes.

Un trabajo diario que revise:

# Rechazadas: necesitan que alguien las mire.
client.get("/invoices", params={"estado": "no_autorizado", "desde": hace_7_dias})
# Atascadas: enviadas hace rato y sin respuesta del SRI.
client.get("/invoices", params={"estado": "enviado"})

Sin esto, una factura rechazada se queda ahí para siempre y nadie se entera hasta que el cliente reclama o llega el cierre del mes.

X-Request-Id, X-RateLimit-Remaining y Deprecation. La primera para soporte, la segunda para ver venir el 429 antes de chocar, la tercera para enterarte de una baja sin leer el changelog.

Antes de producción, comprueba que tu integración sabe qué hacer con:

  • business_not_ready — al negocio le falta configuración fiscal
  • totals_mismatch — vuestros redondeos no coinciden
  • external_id_conflict — la venta ya estaba facturada
  • rate_limited — te pasaste de peticiones
  • Estado no_autorizado — la administración rechazó el comprobante
  • Un timeout en la emisión

Lo que no se prueba, falla el día de más trabajo.

La API puede añadir campos a las respuestas sin avisar. Tu código no debe romperse por encontrar una clave que no esperaba, ni por un valor nuevo en una lista. Ver Versionado.