contadeo-sdk
v0.1.0
Published
SDK TypeScript de la API de Contadeo: facturación electrónica SRI (Ecuador) — emisión individual y por lote, consulta, webhooks firmados
Maintainers
Readme
contadeo-sdk
Cliente TypeScript oficial de la API de Contadeo: facturación electrónica del SRI (Ecuador) — emisión individual y por lote, consulta, descargas y webhooks firmados. Sin dependencias; Node ≥ 18.
npm install contadeo-sdkEmitir una factura
import { Contadeo } from "contadeo-sdk";
const contadeo = new Contadeo({ apiKey: process.env.CONTADEO_API_KEY! }); // cdo_…
const emitida = await contadeo.emitirFactura(
{
emisorId: "…",
certificadoId: "…",
establecimiento: "001",
puntoEmision: "001",
infoFactura: {
tipoIdentificacionComprador: "05",
razonSocialComprador: "Juan Pérez",
identificacionComprador: "0923266183",
totalSinImpuestos: "100.00",
totalDescuento: "0.00",
totalConImpuestos: [
{ codigo: "2", codigoPorcentaje: "4", baseImponible: "100.00", valor: "15.00" },
],
importeTotal: "115.00",
},
detalles: [
{
descripcion: "Servicio de mantenimiento",
cantidad: 1,
precioUnitario: "100.00",
descuento: "0.00",
precioTotalSinImpuesto: "100.00",
impuestos: [
{ codigo: "2", codigoPorcentaje: "4", tarifa: 15, baseImponible: "100.00", valor: "15.00" },
],
},
],
},
{ idempotencyKey: pedido.id }, // reintentar no duplica ni quema secuenciales
);
// La emisión es asíncrona (202). Para flujos puntuales, espera el resultado:
const factura = await contadeo.esperarAutorizacion(emitida.comprobanteId);
if (factura.estado === "AUTORIZADO") {
const pdf = await contadeo.rideUrl(factura.id); // URL prefirmada (~1 h)
}Lote (hasta 100 facturas)
const lote = await contadeo.emitirLote(
{ emisorId, certificadoId, establecimiento: "001", puntoEmision: "001", facturas },
{ idempotencyKey: `corte-${fecha}` }, // reintento del lote entero, seguro
);
// Resultado POR elemento: BORRADOR (encolada) · ERROR · NO_INTENTADA
for (const r of lote.resultados) {
if (r.estado === "ERROR") console.error(r.referencia, r.error);
}Webhooks (recomendado a volumen)
En vez de hacer polling, registra un endpoint y verifica cada entrega:
const wh = await contadeo.crearWebhook({ url: "https://miapp.com/contadeo" });
guardarSecreto(wh.secret); // se muestra UNA sola vez
// En tu servidor — el cuerpo debe llegar CRUDO (express.raw), sin re-serializar:
import { verificarFirmaWebhook } from "contadeo-sdk";
app.post("/contadeo", express.raw({ type: "application/json" }), (req, res) => {
const r = verificarFirmaWebhook(secreto, req.header("x-contadeo-signature"), req.body);
if (!r.valida) return res.status(400).end();
const evento = JSON.parse(req.body.toString("utf8"));
res.status(200).end(); // responde 2xx rápido; procesa aparte
});La verificación es en tiempo constante y rechaza timestamps fuera de la ventana (anti-replay, 5 min por defecto).
Errores
Toda respuesta no-2xx lanza ContadeoApiError con status, mensaje,
problemas[] y reintentable (429/5xx). El polling que se agota lanza
TiempoAgotadoError — la emisión sigue corriendo en segundo plano.
Ambientes
Las cuentas nuevas nacen en el ambiente de Pruebas del SRI (sin validez
tributaria). El campo ambiente de las respuestas dice dónde estás:
1 Pruebas · 2 Producción. Referencia completa de la API:
contadeo.com/referencia-api.html.
