Contanza · Guías
Desarrolladores

API de facturación — emite tu primera factura en 10 minutos

Guía de inicio rápido de la API de Contanza — crea una clave, emite una factura electrónica al SRI con un POST, y recibe el resultado por webhook firmado.

Con la API de Contanza emites comprobantes electrónicos autorizados por el SRI desde tu propio sistema — un ERP, una tienda en línea, un punto de venta — con un solo POST.

Lo que no vas a tener que hacer, porque lo resuelve la plataforma:

  • Calcular totales ni impuestos — se calculan desde los items.
  • Administrar secuenciales — se asignan de forma atómica; ni carreras ni huecos por reintentos.
  • Enviar los datos del emisor en cada request — salen de tu empresa configurada.
  • Manejar tu certificado de firma — el P12 vive cifrado en la plataforma; su clave jamás viaja por la red.
  • Elegir el ambiente del SRI en cada request — es configuración de tu empresa; es imposible emitir a producción por accidente.

Esta guía es el camino rápido. La referencia completa de endpoints, schemas y códigos de error — con ejemplos en cinco lenguajes — vive en /api-docs.

1. Requisitos

Necesitas una cuenta de Contanza con una empresa configurada para emitir:

  • Certificado de firma electrónica (.p12) cargado — Configuración → Firma Electrónica.
  • Establecimiento y punto de emisión — Configuración → Establecimientos.

Si ya emites facturas desde la aplicación, ya lo tienes todo.

2. Crea tu clave API

En Configuración → Claves API, crea una clave. Empieza con ak_ y se muestra una sola vez — guárdala en un gestor de secretos.

Todas las peticiones la llevan como Bearer token:

Authorization: Bearer ak_...

Las claves pertenecen a tu organización: cualquier empresa de tu cuenta puede emitir con la misma clave (eliges cuál con el header X-Taxpayer-Id; si tienes una sola, no hace falta).

3. Emite tu primera factura

curl -X POST https://taxes.ecuanexus.com/api/v1/invoices \
  -H "Authorization: Bearer ak_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "receiver": {
      "taxId": "0992339411001",
      "legalName": "COMERCIAL EJEMPLO S.A.",
      "idType": "04",
      "email": "facturas@ejemplo.com"
    },
    "items": [
      {
        "productCode": "SERV-001",
        "description": "Servicio de consultoría — agosto",
        "quantity": 1,
        "unitPrice": 150,
        "taxes": [
          { "codigo": "2", "codigoPorcentaje": "4", "tarifa": 15, "baseImponible": 150, "valor": 22.5 }
        ]
      }
    ],
    "payments": [{ "method": "20", "amount": 172.5 }]
  }'

La respuesta llega en milisegundos — no espera al SRI:

{
  "id": "7ec46620-6b0c-46ec-afb1-c805702a92e1",
  "accessKey": "0108202601090153910600110010020000000123150670916",
  "sequential": 12,
  "establishment": "001",
  "emissionPoint": "002",
  "status": "QUEUED",
  "links": {
    "status": "/api/v1/invoices/7ec46620-6b0c-46ec-afb1-c805702a92e1",
    "document": "/api/v1/documents/0108202601090153910600110010020000000123150670916"
  }
}

La clave de acceso y el secuencial ya están asignados. La firma y la autorización ante el SRI corren en segundo plano, con reintentos automáticos si el SRI está lento o caído.

El header Idempotency-Key (un UUID que generas tú) te permite reintentar el mismo request sin riesgo: si ya existe una factura con esa llave, la API responde 200 con replayed: true y el documento original — sin emitir dos veces ni consumir otro secuencial. Úsalo siempre.

4. Recibe el resultado por webhook

Registra una URL tuya y Contanza te avisa cuando cada comprobante quede autorizado o rechazado — sin polling:

curl -X POST https://taxes.ecuanexus.com/api/v1/webhooks \
  -H "Authorization: Bearer ak_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://miapp.com/webhooks/taxes",
    "events": ["document.authorized", "document.rejected"]
  }'

La respuesta incluye un secret (whsec_...) que se muestra una sola vez. Cada entrega llega firmada con él:

X-Taxes-Signature: t=1785700000,v1=5f8a...

Verifica la firma sobre el body crudo, antes de parsear el JSON:

import crypto from "node:crypto";
 
function verifyTaxesWebhook(rawBody, signatureHeader, secret) {
  const [t, v1] = signatureHeader.split(",").map((p) => p.split("=")[1]);
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest("hex");
  return (
    Math.abs(Date.now() / 1000 - Number(t)) < 300 &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1))
  );
}

Prueba tu receptor antes de emitir nada real con POST /api/v1/webhooks/{id}/test, que entrega un evento ping por el mismo camino (firma incluida).

Los webhooks avisan de todas las emisiones de tu organización — las de la API, las hechas desde la aplicación, las de WhatsApp y las facturas recurrentes. Un solo receptor cubre todo.

Las entregas fallidas se reintentan con backoff durante horas. Tras 20 fallas consecutivas, el endpoint se desactiva solo.

5. ¿Prefieres polling?

El mismo estado está siempre en el links.status de la respuesta:

curl https://taxes.ecuanexus.com/api/v1/invoices/{id} \
  -H "Authorization: Bearer ak_..."

status recorre QUEUED → SIGNING → SUBMITTING_SRI → AUTHORIZED | REJECTED. Cuando queda AUTHORIZED, la respuesta trae el número de autorización, y en links.document puedes descargar el comprobante:

# JSON canónico
curl .../api/v1/documents/{accessKey} -H "Authorization: Bearer ak_..."
# XML original autorizado
curl .../api/v1/documents/{accessKey} -H "Authorization: Bearer ak_..." -H "Accept: application/xml"

El objeto que recibes por webhook y el del polling son idénticos: escribes un solo parser.

6. Prueba sin miedo

El ambiente del SRI (pruebas o producción) es configuración de tu empresa en la plataforma, no un parámetro del request. Mientras tu empresa esté en ambiente de pruebas, todo lo que emitas por la API va al SRI de pruebas — los flujos son idénticos y ninguna factura tiene validez fiscal.

Siguientes pasos

  • Referencia completa de la API — todos los endpoints, schemas y errores, con ejemplos en Shell, Python, Node, PHP y Ruby.
  • El spec OpenAPI vive en /api/v1/openapi.json — impórtalo en Postman o Insomnia, o genera un cliente tipado con tu herramienta preferida.
  • ¿Algo no funciona como esperabas? Escríbenos por WhatsApp — el botón está aquí abajo.

Actualizado el