Saltar al contenido
DevFact

Documentación

Estados y respuestas

Qué significa cada respuesta, cómo consultar, listar, validar y reintentar.

Qué responde una emisión

  • 201Qué pasó: AUTORIZADO por el SRI.Qué hacer: Guarda xmlAutorizado y entrega el comprobante.
  • 202Qué pasó: El SRI no respondió a tiempo (PENDIENTE, RECIBIDA o EN_PROCESO). El servicio lo termina solo.Qué hacer: Consulta luego o espera el webhook comprobante.autorizado. No lo emitas otra vez.
  • 422Qué pasó: Datos inválidos (COMPROBANTE_INVALIDO) o el SRI lo rechazó (COMPROBANTE_DEVUELTO, COMPROBANTE_NO_AUTORIZADO).Qué hacer: Corrige según details y reintenta (ver abajo).
  • 409Qué pasó: Conflicto de configuración (secuencial sin confirmar, clave de idempotencia con otro contenido…).Qué hacer: Lee error.solucion.
  • 429 / 503Qué pasó: Demasiadas peticiones, serie ocupada o SRI no disponible. No se gastó número.Qué hacer: Reintenta tras Retry-After con la misma Idempotency-Key.

Por defecto la emisión espera hasta 12 segundos la autorización. Con ?esperar=0 responde 202 apenas crea el comprobante (útil en un punto de venta con mucha carga). Otros parámetros: ?ride=true incluye el PDF en base64 en ridePdfBase64 y ?correo=false no envía el correo al comprador.

Consultar un comprobante

Por id o por clave de acceso. Con ?eventos=true trae su recorrido (firmado, recibido, autorizado, correo enviado…), el mismo que ves en el panel.

GET /v1/comprobantes/e9adcca8-8817-4212-911f-9a9f511f8a02
curl "https://api.devfact.fonles.com/v1/comprobantes/e9adcca8-8817-4212-911f-9a9f511f8a02?eventos=true" \
  -H "Authorization: Bearer $DEVFACT_API_KEY"

Esperar un 202

Lo mejor es un webhook. Si no puedes recibirlos, consulta cada pocos segundos y espacia las consultas; el servicio sigue reintentando con el SRI aunque tú no consultes.

esperar-autorizacion.jsJavaScript
async function esperarAutorizacion(id, { maxMinutos = 10 } = {}) {
  const fin = Date.now() + maxMinutos * 60_000;
  let espera = 2_000;
  while (Date.now() < fin) {
    const res = await fetch(`https://api.devfact.fonles.com/v1/comprobantes/${id}`, {
      headers: { Authorization: `Bearer ${process.env.DEVFACT_API_KEY}` },
    });
    const c = await res.json();
    if (["AUTORIZADO", "NO_AUTORIZADO", "DEVUELTA", "ANULADO"].includes(c.estado)) return c;
    await new Promise((r) => setTimeout(r, espera));
    espera = Math.min(espera * 2, 60_000);
  }
  return null; // Sigue en proceso: el servicio lo terminará; revisa más tarde.
}

Listar y buscar

Del más reciente al más antiguo, 50 por página (hasta 100 con limite). Filtros: emisor, tipo, estado (varios separados por coma), desde/hasta (fecha de emisión), ambiente, numero y claveAcceso. Para la página siguiente pasa siguienteCursor como cursor; null es la última.

GET /v1/comprobantes
curl "https://api.devfact.fonles.com/v1/comprobantes?estado=AUTORIZADO&tipo=factura&desde=2026-11-01&hasta=2026-11-30" \
  -H "Authorization: Bearer $DEVFACT_API_KEY"

Validar sin emitir

POST /v1/comprobantes/validar valida el cuerpo, calcula los totales y valida el XML contra el esquema del SRI, sin gastar número, firmar ni enviar nada. Útil para mostrar los totales antes de confirmar una venta. POST /v1/comprobantes/vista-previa devuelve el RIDE de muestra en PDF.

POST /v1/comprobantes/validar
curl -X POST "https://api.devfact.fonles.com/v1/comprobantes/validar" \
  -H "Authorization: Bearer $DEVFACT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "tipo": "factura",
  "comprador": {
    "tipoIdentificacion": "cedula",
    "identificacion": "1710034065",
    "razonSocial": "Carlos Andrade"
  },
  "items": [
    {
      "codigo": "TV-55",
      "descripcion": "Televisor 55 pulgadas",
      "cantidad": 1,
      "precioUnitario": "650.00",
      "descuento": "50.00",
      "iva": "15"
    }
  ],
  "pagos": [
    {
      "formaPago": "tarjetaDebito"
    }
  ]
}'

Cuando el SRI rechaza

Un rechazo trae los mensajes del SRI con su explicación y qué hacer. details.accion resume el camino:

  • CORREGIR_DATOSCorrige y llama a POST /v1/comprobantes/{id}/reintentar con el comprobante corregido: conserva el mismo número y la misma clave de acceso.
  • CONFIGURAR_SECUENCIALError 45: el número ya lo usó otro sistema. Reintentar no sirve: configura el secuencial (en el panel, Emisores → Secuenciales) y emite uno nuevo.
422 Unprocessable EntityJSON
{
  "error": {
    "code": "COMPROBANTE_DEVUELTO",
    "message": "El SRI devolvió el comprobante: 65 FECHA EMISIÓN EXTEMPORANEA",
    "source": "sri",
    "details": {
      "estado": "DEVUELTA",
      "mensajes": [{
        "identificador": "65",
        "mensaje": "FECHA EMISIÓN EXTEMPORANEA",
        "titulo": "El comprobante se envió fuera de plazo",
        "solucion": "Emita con la fecha de hoy…",
        "reintentable": true
      }],
      "accion": "CORREGIR_DATOS",
      "sugerencia": "Corrija lo que indica el SRI y llame a POST /v1/comprobantes/79a31dab-…/reintentar"
    },
    "requestId": "1e676c55-5ebf-4f1b-9811-9c6c86258ed4",
    "docUrl": "https://api.devfact.fonles.com/v1/errores/COMPROBANTE_DEVUELTO",
    "solucion": "Corrija lo que indica el SRI y llame a POST /v1/comprobantes/79a31dab-…/reintentar"
  },
  "comprobante": { "id": "79a31dab-8d18-49f0-b7ff-b3083c3ca888", "estado": "DEVUELTA", "numero": "001-001-000004522", "…": "…" }
}
POST /v1/comprobantes/{id}/reintentar
curl -X POST "https://api.devfact.fonles.com/v1/comprobantes/79a31dab-8d18-49f0-b7ff-b3083c3ca888/reintentar" \
  -H "Authorization: Bearer $DEVFACT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "items": [
    {
      "descripcion": "Café americano",
      "cantidad": 2,
      "precioUnitario": "2.50",
      "iva": "15"
    }
  ],
  "pagos": [
    {
      "formaPago": "efectivo"
    }
  ]
}'

Un error de validación nunca llega al SRI ni gasta número: details.issues dice qué campo corregir.

422 COMPROBANTE_INVALIDOJSON
{
  "error": {
    "code": "COMPROBANTE_INVALIDO",
    "message": "Comprobante inválido: items.0.cantidad: Debe ser mayor que cero; pagos: Debe tener al menos 1 elemento(s)",
    "source": "validacion",
    "details": {
      "issues": [
        { "path": "items.0.cantidad", "code": "MONTO_DEBE_SER_POSITIVO", "message": "Debe ser mayor que cero" },
        { "path": "pagos", "code": "LISTA_VACIA", "message": "Debe tener al menos 1 elemento(s)" }
      ]
    },
    "requestId": "2e1fa07e-1a67-4788-8860-092cdaf2fe85",
    "docUrl": "https://api.devfact.fonles.com/v1/errores/COMPROBANTE_INVALIDO"
  }
}