DavyCorp APIs

Comprobantes recibidos

Recupera facturas, liquidaciones, notas y retenciones del portal SRI en línea. Cada descarga es un trabajo asíncrono.

BASE URL https://apis.davycorp.ec/v2
Demo. Igual que POST /v2/validar-cedula-ruc-demo: solo verifyApiUser. El dueño es el id del API user. Una URL demo no lee ni descarga trabajos de otra modalidad ni de otro usuario.
Portal real. Demo consulta el SRI de verdad: no es un simulador. Si envías un RUC y una clave reales, se entra al portal con ellos.
POST /docs-recibidos/demo DEMO

Autenticación

AuthorizationBearer TU_API_KEYrequerido
Cuerpo JSON
CampoTipoObligatorioDescripción
rucstringSíRUC con el que se entra al portal del SRI. No se guarda en la base.
clavestringSíContraseña del portal del SRI. Solo vive en memoria mientras el trabajo corre. No la compartas ni la publiques.
aniostringNoAño del período. Si se omite, se usa el período que deje el formulario del SRI.
messtringNoMes numérico, por ejemplo 1 o 6. Si se omite, igual que anio.
tipostringNoPor defecto factura. Valores: factura, liquidacion, nota de credito (o credito, nc), nota de debito (o debito, nd), retencion. Se pueden separar por coma. Un valor desconocido responde 400.
httpHandoffbooleanNoPor defecto true: el navegador resuelve la consulta y la descarga sigue por HTTP. Con false solo se baja la primera página por clic.
soloReportebooleanNoPor defecto false. Con true baja el TXT y no vuelve a pedir los XML.
esperarbooleanNoPor defecto false (asíncrono, HTTP 202). Con true, o con la query ?esperar=true, el POST espera el trabajo hasta SRI_ESPERA_HTTP_MS (máx. 120 s). Si se agota, responde 202 con el mismo trabajo y hay que seguir consultando el estado.
Clave del SRI. clave es la contraseña del portal del SRI. No la compartas, no la publiques y no la pongas en repositorios ni en logs.
Ejemplos de consumo
cURL
fetch
Python
curl -X POST "https://apis.davycorp.ec/v2/docs-recibidos/demo" \
  -H "Authorization: Bearer TU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ruc": "1790000000001",
    "clave": "TU_CLAVE_SRI",
    "anio": "2026",
    "mes": "1",
    "tipo": "factura"
  }'
const response = await fetch(
  "https://apis.davycorp.ec/v2/docs-recibidos/demo",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer TU_API_KEY",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      ruc: "1790000000001",
      clave: "TU_CLAVE_SRI",
      anio: "2026",
      mes: "1",
      tipo: "factura"
    })
  }
);

const data = await response.json();
console.log(data);
import requests

response = requests.post(
    "https://apis.davycorp.ec/v2/docs-recibidos/demo",
    headers={
        "Authorization": "Bearer TU_API_KEY",
    },
    json={
        "ruc": "1790000000001",
        "clave": "TU_CLAVE_SRI",
        "anio": "2026",
        "mes": "1",
        "tipo": "factura",
    },
    timeout=30,
)

print(response.status_code)
print(response.json())
Respuestas
202
400
401 · 403
429
500
// 202 — trabajo creado (los valores son ilustrativos)
{
  "job_id": "ID_DEL_TRABAJO",
  "estado": "pendiente",
  "mensaje": "Descarga iniciada. Consulta el estado con el mismo prefijo de modalidad."
}
// 400 — faltan campos obligatorios
{ "error": "ruc y clave son obligatorios" }

// 400 — tipo desconocido
{ "error": "tipo \"xyz\" no reconocido (usa: factura, liquidacion, credito, debito, retencion)" }
// 401 — sin header Authorization
{ "error": "API Key requerida" }

// 403 — API key inválida
{ "success": false, "error": "Api user inválido" }
// 429 — el API user llegó a su límite de consultas
{ "error": "Límite de consultas alcanzado", "status": false }
// 500 — fallo interno al crear el trabajo
{ "error": "MENSAJE_DEL_SERVIDOR", "status": false }

El POST normalmente responde 202 porque el trabajo es asíncrono: guarda el identificador y consulta el estado con las operaciones de abajo. Los nombres y valores del ejemplo 202 son una referencia, no valores fijos.

Operaciones del trabajo — demo
MétodoURLPara qué
GET/v2/docs-recibidos/demo/:jobIdEstado
GET/v2/docs-recibidos/demo/:jobId/comprobantesListado JSON del reporte
GET/v2/docs-recibidos/demo/:jobId/archivoZIP (binario)
POST/v2/docs-recibidos/demo/:jobId/cancelarCancelar
# Estado
curl "https://apis.davycorp.ec/v2/docs-recibidos/demo/JOB_ID" \
  -H "Authorization: Bearer TU_API_KEY"

# Comprobantes (JSON)
curl "https://apis.davycorp.ec/v2/docs-recibidos/demo/JOB_ID/comprobantes" \
  -H "Authorization: Bearer TU_API_KEY"

# ZIP: se guarda como archivo, no se lee como JSON
curl -L "https://apis.davycorp.ec/v2/docs-recibidos/demo/JOB_ID/archivo" \
  -H "Authorization: Bearer TU_API_KEY" \
  -o comprobantes.zip

# Cancelar
curl -X POST "https://apis.davycorp.ec/v2/docs-recibidos/demo/JOB_ID/cancelar" \
  -H "Authorization: Bearer TU_API_KEY"
// Estado de un trabajo terminado (ilustrativo)
{
  "id": "JOB_ID",
  "estado": "completado",
  "modalidad": "demo",
  "zip_url": "/v2/docs-recibidos/demo/JOB_ID/archivo",
  "archivoUrl": "/v2/docs-recibidos/demo/JOB_ID/archivo",
  "comprobantesUrl": "/v2/docs-recibidos/demo/JOB_ID/comprobantes",
  "error": null,
  "creado": "2026-10-26T18:00:00.000Z",
  "terminado": "2026-10-26T18:04:12.000Z"
}

Archivo. Se descarga cuando estado es completado o parcial, y la respuesta es el ZIP binario. Con el trabajo en curso responde 409. Si el temporal ya se limpió, o el trabajo es de otro usuario o modalidad, responde 404.

Comprobantes. Una lista vacía es un período sin documentos, no un error. Si el trabajo sigue en ejecución responde 409.

Cancelar. Un trabajo pendiente pasa a fallido sin entrar al portal. Si ya está procesando, se detiene antes del siguiente intento. Uno terminado responde 409. Los GET no incrementan el cupo del API user.

Comercial. Igual que POST /v2/validar-cedula-ruc y /v2/whatsapp/send/comercial: solo verifyApiUser. No pasa por verifyLicense. El dueño de los trabajos es el id del API user autenticado.
POST /docs-recibidos/comercial COMERCIAL

Autenticación

AuthorizationBearer TU_API_KEYrequerido
Cuerpo JSON
CampoTipoObligatorioDescripción
rucstringSíRUC con el que se entra al portal del SRI. No se guarda en la base.
clavestringSíContraseña del portal del SRI. Solo vive en memoria mientras el trabajo corre. No la compartas ni la publiques.
aniostringNoAño del período. Si se omite, se usa el período que deje el formulario del SRI.
messtringNoMes numérico, por ejemplo 1 o 6. Si se omite, igual que anio.
tipostringNoPor defecto factura. Valores: factura, liquidacion, nota de credito (o credito, nc), nota de debito (o debito, nd), retencion. Se pueden separar por coma. Un valor desconocido responde 400.
httpHandoffbooleanNoPor defecto true: el navegador resuelve la consulta y la descarga sigue por HTTP. Con false solo se baja la primera página por clic.
soloReportebooleanNoPor defecto false. Con true baja el TXT y no vuelve a pedir los XML.
esperarbooleanNoPor defecto false (asíncrono, HTTP 202). Con true, o con la query ?esperar=true, el POST espera el trabajo hasta SRI_ESPERA_HTTP_MS (máx. 120 s). Si se agota, responde 202 con el mismo trabajo y hay que seguir consultando el estado.
Clave del SRI. clave es la contraseña del portal del SRI. No la compartas, no la publiques y no la pongas en repositorios ni en logs.
Ejemplos de consumo
cURL
fetch
Python
curl -X POST "https://apis.davycorp.ec/v2/docs-recibidos/comercial" \
  -H "Authorization: Bearer TU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ruc": "1790000000001",
    "clave": "TU_CLAVE_SRI",
    "anio": "2026",
    "mes": "1",
    "tipo": "factura,retencion"
  }'
const response = await fetch(
  "https://apis.davycorp.ec/v2/docs-recibidos/comercial",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer TU_API_KEY",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      ruc: "1790000000001",
      clave: "TU_CLAVE_SRI",
      anio: "2026",
      mes: "1",
      tipo: "factura,retencion"
    })
  }
);

const data = await response.json();
console.log(data);
import requests

response = requests.post(
    "https://apis.davycorp.ec/v2/docs-recibidos/comercial",
    headers={
        "Authorization": "Bearer TU_API_KEY",
    },
    json={
        "ruc": "1790000000001",
        "clave": "TU_CLAVE_SRI",
        "anio": "2026",
        "mes": "1",
        "tipo": "factura,retencion",
    },
    timeout=30,
)

print(response.status_code)
print(response.json())
Respuestas
202
400
401 · 403
429
500
// 202 — trabajo creado (los valores son ilustrativos)
{
  "job_id": "ID_DEL_TRABAJO",
  "estado": "pendiente",
  "mensaje": "Descarga iniciada. Consulta el estado con el mismo prefijo de modalidad."
}
// 400 — faltan campos obligatorios
{ "error": "ruc y clave son obligatorios" }

// 400 — tipo desconocido
{ "error": "tipo \"xyz\" no reconocido (usa: factura, liquidacion, credito, debito, retencion)" }
// 401 — sin header Authorization
{ "error": "API Key requerida" }

// 403 — API key inválida
{ "success": false, "error": "Api user inválido" }
// 429 — el API user llegó a su límite de consultas
{ "error": "Límite de consultas alcanzado", "status": false }
// 500 — fallo interno al crear el trabajo
{ "error": "MENSAJE_DEL_SERVIDOR", "status": false }

El POST normalmente responde 202 porque el trabajo es asíncrono: guarda el identificador y consulta el estado con las operaciones de abajo. Los nombres y valores del ejemplo 202 son una referencia, no valores fijos.

Operaciones del trabajo — comercial
MétodoURLPara qué
GET/v2/docs-recibidos/comercial/:jobIdEstado
GET/v2/docs-recibidos/comercial/:jobId/comprobantesListado JSON del reporte
GET/v2/docs-recibidos/comercial/:jobId/archivoZIP (binario)
POST/v2/docs-recibidos/comercial/:jobId/cancelarCancelar
# Estado
curl "https://apis.davycorp.ec/v2/docs-recibidos/comercial/JOB_ID" \
  -H "Authorization: Bearer TU_API_KEY"

# Comprobantes (JSON)
curl "https://apis.davycorp.ec/v2/docs-recibidos/comercial/JOB_ID/comprobantes" \
  -H "Authorization: Bearer TU_API_KEY"

# ZIP: se guarda como archivo, no se lee como JSON
curl -L "https://apis.davycorp.ec/v2/docs-recibidos/comercial/JOB_ID/archivo" \
  -H "Authorization: Bearer TU_API_KEY" \
  -o comprobantes.zip

# Cancelar
curl -X POST "https://apis.davycorp.ec/v2/docs-recibidos/comercial/JOB_ID/cancelar" \
  -H "Authorization: Bearer TU_API_KEY"
// Estado de un trabajo terminado (ilustrativo)
{
  "id": "JOB_ID",
  "estado": "completado",
  "modalidad": "comercial",
  "zip_url": "/v2/docs-recibidos/comercial/JOB_ID/archivo",
  "archivoUrl": "/v2/docs-recibidos/comercial/JOB_ID/archivo",
  "comprobantesUrl": "/v2/docs-recibidos/comercial/JOB_ID/comprobantes",
  "error": null,
  "creado": "2026-10-26T18:00:00.000Z",
  "terminado": "2026-10-26T18:04:12.000Z"
}

Archivo. Se descarga cuando estado es completado o parcial, y la respuesta es el ZIP binario. Con el trabajo en curso responde 409. Si el temporal ya se limpió, o el trabajo es de otro usuario o modalidad, responde 404.

Comprobantes. Una lista vacía es un período sin documentos, no un error. Si el trabajo sigue en ejecución responde 409.

Cancelar. Un trabajo pendiente pasa a fallido sin entrar al portal. Si ya está procesando, se detiene antes del siguiente intento. Uno terminado responde 409. Los GET no incrementan el cupo del API user.

Estados, reintentos y archivos
EstadoSignificado
pendienteEn cola. La clave está solo en memoria de este proceso.
procesandoLogin y descarga en curso. Hay un solo trabajo a la vez.
completadoLa consulta al SRI terminó. Puede ser período vacío (total 0) o ZIP completo. archivoUrl / zip_url apuntan a GET /{jobId}/archivo si el temporal sigue. No se marca completado solo por haber enviado la petición.
parcialHay listado, pero faltan XML. El ZIP (si existe) no se presenta como completo. completo es false.
fallidoError o reinicio del servidor. No se vuelve a intentar el login solo.
canceladoEl cliente pidió parar.

Reintentos. INTENTOS vale 6. No se reintenta un rechazo explícito de credenciales ni un Chromium que no arranca. Dentro de una página, SRI_XML_WORKERS vale 2. SRI_JOB_TIMEOUT_MS en 0 no corta el trabajo.

Archivos. XML, TXT y ZIP viven en un directorio temporal por trabajo (os.tmpdir()), no en el repo. El listado JSON se guarda en PostgreSQL (metadatos, no el XML). El ZIP incluye xml/, comprobantes.json y resultado.json. Se borra al terminar la transmisión o al vencer SRI_TMP_TTL_MS (30 min por defecto). El nombre del ZIP es comprobantes_<TIPO>_<anio>_<mes>.zip.

Modo esperar. Sin esperar el POST responde 202 de inmediato. Con esperar=true espera el trabajo real; si el tiempo HTTP se agota, 202 con esperaAgotada: true y el mismo jobId. Hay que seguir consultando GET estado. Swagger no descarga el ZIP automáticamente.

Reinicio. Al arrancar, lo que quedó pendiente o procesando pasa a fallido. La clave no está en PostgreSQL, así que el proceso no puede volver a entrar al SRI por su cuenta.

URL anterior. El servicio suelto usaba POST /descargar, GET /estado/:id y GET /archivo/:id en su propio puerto. Ahora viven bajo /v2/docs-recibidos, con el sufijo /demo o /comercial.
Mapa de las dos modalidades
ModalidadCrear trabajoMiddlewaresDueño
DemoPOST /v2/docs-recibidos/demoverifyApiUserid del API user
ComercialPOST /v2/docs-recibidos/comercialverifyApiUserid del API user

Estado, archivo y cancelación repiten esa misma cadena. Cruzar modalidad o dueño responde 404 con {"error":"Job no encontrado"} o {"error":"Archivo no disponible"}.

Códigos que devuelve el servidor
HTTPCuándoCuerpo
202Trabajo creado (asíncrono), espera HTTP agotada, o cancelación diferidajob_id, estado, mensaje, opcionalmente esperaAgotada
200Estado, comprobantes, ZIP, espera terminada, o cancelación de un pendienteJSON del trabajo, listado, o archivo ZIP
400Faltan ruc y clave, o el tipo no existeerror
401Sin header Authorization{"error":"API Key requerida"}
403API key inválidasuccess: false, error
404Trabajo de otro dueño o modalidad, o ZIP que no estáJob no encontrado o Archivo no disponible
409Cancelar un trabajo ya terminado{"error":"El trabajo ya terminó"}
429El API user llegó a usage_limit{"error":"Límite de consultas alcanzado","status":false}
500Fallo interno al crear, consultar o guardarerror y status: false

Un fallo del portal queda en error del trabajo y no detiene el proceso de las otras APIs. La descarga masiva contra el SRI no forma parte de esta integración: un trabajo, un período.