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.
Autenticación
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
ruc | string | Sí | RUC con el que se entra al portal del SRI. No se guarda en la base. |
clave | string | Sí | Contraseña del portal del SRI. Solo vive en memoria mientras el trabajo corre. No la compartas ni la publiques. |
anio | string | No | Año del período. Si se omite, se usa el período que deje el formulario del SRI. |
mes | string | No | Mes numérico, por ejemplo 1 o 6. Si se omite, igual que anio. |
tipo | string | No | Por 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. |
httpHandoff | boolean | No | Por defecto true: el navegador resuelve la consulta y la descarga sigue por HTTP. Con false solo se baja la primera página por clic. |
soloReporte | boolean | No | Por defecto false. Con true baja el TXT y no vuelve a pedir los XML. |
esperar | boolean | No | Por 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 es la contraseña del portal del SRI. No la compartas, no la publiques y no la pongas en repositorios ni en logs.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())// 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.
| Método | URL | Para qué |
|---|---|---|
| GET | /v2/docs-recibidos/demo/:jobId | Estado |
| GET | /v2/docs-recibidos/demo/:jobId/comprobantes | Listado JSON del reporte |
| GET | /v2/docs-recibidos/demo/:jobId/archivo | ZIP (binario) |
| POST | /v2/docs-recibidos/demo/:jobId/cancelar | Cancelar |
# 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.
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.
Autenticación
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
ruc | string | Sí | RUC con el que se entra al portal del SRI. No se guarda en la base. |
clave | string | Sí | Contraseña del portal del SRI. Solo vive en memoria mientras el trabajo corre. No la compartas ni la publiques. |
anio | string | No | Año del período. Si se omite, se usa el período que deje el formulario del SRI. |
mes | string | No | Mes numérico, por ejemplo 1 o 6. Si se omite, igual que anio. |
tipo | string | No | Por 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. |
httpHandoff | boolean | No | Por defecto true: el navegador resuelve la consulta y la descarga sigue por HTTP. Con false solo se baja la primera página por clic. |
soloReporte | boolean | No | Por defecto false. Con true baja el TXT y no vuelve a pedir los XML. |
esperar | boolean | No | Por 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 es la contraseña del portal del SRI. No la compartas, no la publiques y no la pongas en repositorios ni en logs.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())// 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.
| Método | URL | Para qué |
|---|---|---|
| GET | /v2/docs-recibidos/comercial/:jobId | Estado |
| GET | /v2/docs-recibidos/comercial/:jobId/comprobantes | Listado JSON del reporte |
| GET | /v2/docs-recibidos/comercial/:jobId/archivo | ZIP (binario) |
| POST | /v2/docs-recibidos/comercial/:jobId/cancelar | Cancelar |
# 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.
| Estado | Significado |
|---|---|
pendiente | En cola. La clave está solo en memoria de este proceso. |
procesando | Login y descarga en curso. Hay un solo trabajo a la vez. |
completado | La 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. |
parcial | Hay listado, pero faltan XML. El ZIP (si existe) no se presenta como completo. completo es false. |
fallido | Error o reinicio del servidor. No se vuelve a intentar el login solo. |
cancelado | El 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.
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.
| Modalidad | Crear trabajo | Middlewares | Dueño |
|---|---|---|---|
| Demo | POST /v2/docs-recibidos/demo | verifyApiUser | id del API user |
| Comercial | POST /v2/docs-recibidos/comercial | verifyApiUser | id 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"}.
| HTTP | Cuándo | Cuerpo |
|---|---|---|
| 202 | Trabajo creado (asíncrono), espera HTTP agotada, o cancelación diferida | job_id, estado, mensaje, opcionalmente esperaAgotada |
| 200 | Estado, comprobantes, ZIP, espera terminada, o cancelación de un pendiente | JSON del trabajo, listado, o archivo ZIP |
| 400 | Faltan ruc y clave, o el tipo no existe | error |
| 401 | Sin header Authorization | {"error":"API Key requerida"} |
| 403 | API key inválida | success: false, error |
| 404 | Trabajo de otro dueño o modalidad, o ZIP que no está | Job no encontrado o Archivo no disponible |
| 409 | Cancelar un trabajo ya terminado | {"error":"El trabajo ya terminó"} |
| 429 | El API user llegó a usage_limit | {"error":"Límite de consultas alcanzado","status":false} |
| 500 | Fallo interno al crear, consultar o guardar | error 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.