Apariencia
Comprobantes electrónicos
Validez de comprobantes de pago electrónicos (CPE) en SUNAT, validación masiva desde Excel o TXT y descarga de CDR, XML y PDF.
ConsultaPe nunca devuelve ni registra tu clave SOL.
Catálogos
Tipos de comprobante (tipo)
tipo | Comprobante |
|---|---|
01 | Factura electrónica |
03 | Boleta de venta electrónica |
04 | Liquidación de compra |
07 | Nota de crédito |
08 | Nota de débito |
09 | Guía de remisión remitente (solo XML/PDF) |
31 | Guía de remisión transportista (solo XML/PDF) |
R1 | Recibo por honorarios |
R7 | Nota de crédito de recibo por honorarios |
Estados
| Campo | Valores |
|---|---|
estado_cp | 0 NO EXISTE · 1 ACEPTADO · 2 ANULADO · 3 AUTORIZADO · 4 NO AUTORIZADO |
estado_ruc | 00 ACTIVO · 01 BAJA PROVISIONAL · 10 BAJA DEFINITIVA · … (catálogo SUNAT) |
condicion_domicilio | 00 HABIDO · 12 NO HABIDO · … (catálogo SUNAT) |
Cada código viene acompañado de su texto (estado_cp_texto, estado_ruc_texto, condicion_texto). Si SUNAT devuelve un código que no está en el catálogo, el texto es el propio código.
Credenciales SOL
CDR, XML y PDF necesitan una clave SOL. Envía una de estas opciones:
usuario_sol+clave_sol(yruc) en cada llamada, ocredencial_id: el UUID de una credencial guardada en app.consultape.pro (sección Credenciales). El RUC de login es el de la credencial y la clave queda cifrada en ConsultaPe.
Usuario SOL secundario
Crea en SUNAT Operaciones en Línea un usuario secundario con permiso solo a Consulta de comprobantes de pago y úsalo aquí, en lugar de tu usuario principal.
Validez de un comprobante
POST /v1/cpe/validez · Módulo cpe.validez
Estado de un comprobante en SUNAT (servicio "Consulta integrada de validez").
| Parámetro | En | Tipo | Requerido | Descripción |
|---|---|---|---|---|
ruc_emisor | cuerpo | string | Sí | RUC del emisor (11 dígitos válidos). |
tipo | cuerpo | string | Sí | 01, 03, 04, 07, 08, R1 o R7. |
serie | cuerpo | string | Sí | 4 caracteres alfanuméricos (F001, B001, E001…). |
numero | cuerpo | string | Sí | 1 a 8 dígitos (se aceptan ceros a la izquierda). |
fecha_emision | cuerpo | string | Sí | YYYY-MM-DD. |
monto | cuerpo | number | string | Según tipo | Importe total. SUNAT lo exige para facturas y boletas. |
credencial_id | cuerpo | string (UUID) | No | Credencial con client_id/client_secret de API SUNAT propios. Si no se envía, se usa la cuenta de ConsultaPe. |
bash
curl -X POST "https://api.consultape.pro/v1/cpe/validez" \
-H "Authorization: Bearer $CONSULTAPE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ruc_emisor": "20100070970", "tipo": "01", "serie": "F001", "numero": "123", "fecha_emision": "2024-01-15", "monto": 118.00}'js
const respuesta = await fetch('https://api.consultape.pro/v1/cpe/validez', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CONSULTAPE_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
ruc_emisor: '20100070970',
tipo: '01',
serie: 'F001',
numero: '123',
fecha_emision: '2024-01-15',
monto: 118.00,
}),
});
const datos = await respuesta.json();
if (datos.success) console.log(datos.result);
else console.error(respuesta.status, datos.message);php
<?php
$ch = curl_init('https://api.consultape.pro/v1/cpe/validez');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CONSULTAPE_TOKEN'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'ruc_emisor' => '20100070970',
'tipo' => '01',
'serie' => 'F001',
'numero' => '123',
'fecha_emision' => '2024-01-15',
'monto' => 118.00,
]),
CURLOPT_TIMEOUT => 120,
]);
$cuerpo = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$datos = json_decode($cuerpo, true);
if ($datos['success']) {
print_r($datos['result']);
} else {
echo "Error $http: {$datos['message']}";
}python
import os
import requests
r = requests.post(
"https://api.consultape.pro/v1/cpe/validez",
headers={"Authorization": f"Bearer {os.environ['CONSULTAPE_TOKEN']}"},
json={
"ruc_emisor": "20100070970",
"tipo": "01",
"serie": "F001",
"numero": "123",
"fecha_emision": "2024-01-15",
"monto": 118.00,
},
timeout=120,
)
datos = r.json()
print(datos["result"] if datos["success"] else f"Error {r.status_code}: {datos['message']}")Respuesta (comprobante aceptado):
json
{
"success": true,
"message": "La Factura Electrónica F001-123 es un comprobante de pago válido.",
"result": {
"id": "0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e",
"comprobante": "F001-123",
"ruc_emisor": "20100070970",
"tipo": "01",
"tipo_texto": "FACTURA ELECTRONICA",
"serie": "F001",
"numero": "123",
"fecha_emision": "2024-01-15",
"monto": 118,
"estado_cp": "1",
"estado_cp_texto": "ACEPTADO",
"estado_ruc": "00",
"estado_ruc_texto": "ACTIVO",
"condicion_domicilio": "00",
"condicion_texto": "HABIDO",
"observaciones": [],
"mensaje": "La Factura Electrónica F001-123 es un comprobante de pago válido.",
"fuente": "consultape.pro",
"consultado_at": "2026-10-04T15:20:11.000Z"
}
}- Si
estado_cpes distinto de1,estado_ruc*ycondicion*pueden venir ennullporque SUNAT no los devuelve. - Un comprobante que no existe es una consulta exitosa (
success: true,estado_cp: "0",estado_cp_texto: "NO EXISTE") y consume cuota.
Fallas (HTTP 200, success: false):
SUNAT: <mensaje de SUNAT>(por ejemplo, datos inconsistentes).SUNAT no respondió. Intenta nuevamente en unos minutos.El servicio de validación de SUNAT no está configurado. Contacta con soporte.
Validez masiva
Valida cientos o miles de comprobantes a partir de un archivo. El proceso corre en segundo plano: subes el archivo, consultas el progreso y descargas el resultado en Excel.
Subir archivo
POST /v1/cpe/validez-masiva · Módulo cpe.validez_masiva
Cuerpo multipart/form-data:
| Parámetro | En | Tipo | Requerido | Descripción |
|---|---|---|---|---|
archivo | formulario | archivo | Sí | .xlsx, .xls o .txt. Máximo 5 MB y 5000 comprobantes. |
credencial_id | formulario | string (UUID) | No | Credencial de API SUNAT propia. |
Formatos:
- Excel (
.xlsx/.xls): primera hoja, la fila 1 son encabezados. Columnas A a F:RUC emisor | Tipo | Serie | Número | Fecha de emisión | Monto. La fecha puede ser fecha de Excel o textodd/mm/aaaa,dd-mm-aaaaoaaaa-mm-dd. Descarga la plantilla. - Texto (
.txt, formato de SUNAT): una línea por comprobante,RUC|TIPO|SERIE|NUMERO|FECHA(dd/mm/aaaa)|IMPORTE:
20100070970|01|F001|123|15/01/2024|118.00
20100070970|03|B001|55|16/01/2024|45.00Reglas:
- La carga cuenta como 1 consulta del módulo, pero las filas válidas no pueden superar las consultas que te quedan en el mes. Si las superan: 429
Tu plan tiene 120 consultas disponibles este mes y el archivo trae 300 comprobantes. - Las filas inválidas se omiten y se informan en
filas_invalidas(se listan hasta 50). Si ninguna fila es válida: 400. - Las filas repetidas (mismo RUC, tipo, serie y número) se validan una sola vez.
bash
curl -X POST "https://api.consultape.pro/v1/cpe/validez-masiva" \
-H "Authorization: Bearer $CONSULTAPE_TOKEN" \
-F "[email protected]"js
import { readFile } from 'node:fs/promises';
const formulario = new FormData();
formulario.append('archivo', new Blob([await readFile('comprobantes.xlsx')]), 'comprobantes.xlsx');
const respuesta = await fetch('https://api.consultape.pro/v1/cpe/validez-masiva', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CONSULTAPE_TOKEN}`,
},
body: formulario,
});
const datos = await respuesta.json();
if (datos.success) console.log(datos.result);
else console.error(respuesta.status, datos.message);php
<?php
$ch = curl_init('https://api.consultape.pro/v1/cpe/validez-masiva');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CONSULTAPE_TOKEN')],
CURLOPT_POSTFIELDS => ['archivo' => new CURLFile('comprobantes.xlsx')],
CURLOPT_TIMEOUT => 120,
]);
$cuerpo = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$datos = json_decode($cuerpo, true);
if ($datos['success']) {
print_r($datos['result']);
} else {
echo "Error $http: {$datos['message']}";
}python
import os
import requests
with open("comprobantes.xlsx", "rb") as f:
r = requests.post(
"https://api.consultape.pro/v1/cpe/validez-masiva",
headers={"Authorization": f"Bearer {os.environ['CONSULTAPE_TOKEN']}"},
files={"archivo": f},
timeout=120,
)
datos = r.json()
print(datos["result"] if datos["success"] else f"Error {r.status_code}: {datos['message']}")Respuesta:
json
{
"success": true,
"message": "Archivo recibido: 248 comprobantes en cola de validación",
"result": {
"lote": {
"id": "0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e",
"nombre_archivo": "comprobantes.xlsx",
"total": 248,
"procesados": 0,
"validos": 0,
"con_observacion": 0,
"porcentaje": 0,
"estado": "pendiente",
"mensaje": null,
"created_at": "2026-10-04T15:20:11.000Z",
"terminado_at": null
},
"filas_invalidas": [
{ "fila": 7, "error": "RUC emisor inválido" },
{ "fila": 12, "error": "Fecha de emisión inválida" }
],
"total_filas_invalidas": 2
}
}Errores 400 frecuentes: El archivo debe ser .xlsx, .xls o .txt.
Listar mis lotes
GET /v1/cpe/validez-masiva · Módulo cpe.validez_masiva
Del más reciente al más antiguo. No consume cuota.
| Parámetro | En | Tipo | Requerido | Descripción |
|---|---|---|---|---|
pagina | query | number | No | Página, desde 1. |
por_pagina | query | number | No | Máximo 100. Por defecto 20. |
bash
curl "https://api.consultape.pro/v1/cpe/validez-masiva?pagina=1&por_pagina=20" \
-H "Authorization: Bearer $CONSULTAPE_TOKEN"js
const respuesta = await fetch('https://api.consultape.pro/v1/cpe/validez-masiva?pagina=1&por_pagina=20', {
headers: {
Authorization: `Bearer ${process.env.CONSULTAPE_TOKEN}`,
},
});
const datos = await respuesta.json();
if (datos.success) console.log(datos.result);
else console.error(respuesta.status, datos.message);php
<?php
$ch = curl_init('https://api.consultape.pro/v1/cpe/validez-masiva?pagina=1&por_pagina=20');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CONSULTAPE_TOKEN')],
CURLOPT_TIMEOUT => 120,
]);
$cuerpo = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$datos = json_decode($cuerpo, true);
if ($datos['success']) {
print_r($datos['result']);
} else {
echo "Error $http: {$datos['message']}";
}python
import os
import requests
r = requests.get(
"https://api.consultape.pro/v1/cpe/validez-masiva",
params={
"pagina": 1,
"por_pagina": 20,
},
headers={"Authorization": f"Bearer {os.environ['CONSULTAPE_TOKEN']}"},
timeout=120,
)
datos = r.json()
print(datos["result"] if datos["success"] else f"Error {r.status_code}: {datos['message']}")Respuesta:
json
{
"success": true,
"message": "Operación exitosa",
"result": {
"items": [
{
"id": "0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e",
"nombre_archivo": "comprobantes.xlsx",
"total": 248,
"procesados": 248,
"validos": 240,
"con_observacion": 8,
"porcentaje": 100,
"estado": "completado",
"mensaje": null,
"created_at": "2026-10-04T15:20:11.000Z",
"terminado_at": "2026-10-04T15:22:40.000Z"
}
],
"total": 1,
"pagina": 1,
"por_pagina": 20
}
}estado:pendiente→procesando→completadooerror.validos: comprobantes ACEPTADOS o AUTORIZADOS.con_observacion: el resto de procesados (no existe, anulado, no autorizado o error al consultar).
Progreso y resultados de un lote
GET /v1/cpe/validez-masiva/{id} · Módulo cpe.validez_masiva
Progreso y resultados paginados, en el orden del archivo. Consulta cada 2–3 segundos mientras estado sea pendiente o procesando.
| Parámetro | En | Tipo | Requerido | Descripción |
|---|---|---|---|---|
id | ruta | string (UUID) | Sí | Id del lote. Un lote de otro usuario responde 404. |
pagina | query | number | No | Página, desde 1. |
por_pagina | query | number | No | Máximo 100. Por defecto 50. |
filtro | query | string | No | todos (por defecto), validos, observados o errores. |
bash
curl "https://api.consultape.pro/v1/cpe/validez-masiva/0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e?pagina=1&por_pagina=50&filtro=todos" \
-H "Authorization: Bearer $CONSULTAPE_TOKEN"js
const respuesta = await fetch('https://api.consultape.pro/v1/cpe/validez-masiva/0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e?pagina=1&por_pagina=50&filtro=todos', {
headers: {
Authorization: `Bearer ${process.env.CONSULTAPE_TOKEN}`,
},
});
const datos = await respuesta.json();
if (datos.success) console.log(datos.result);
else console.error(respuesta.status, datos.message);php
<?php
$ch = curl_init('https://api.consultape.pro/v1/cpe/validez-masiva/0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e?pagina=1&por_pagina=50&filtro=todos');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CONSULTAPE_TOKEN')],
CURLOPT_TIMEOUT => 120,
]);
$cuerpo = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$datos = json_decode($cuerpo, true);
if ($datos['success']) {
print_r($datos['result']);
} else {
echo "Error $http: {$datos['message']}";
}python
import os
import requests
r = requests.get(
"https://api.consultape.pro/v1/cpe/validez-masiva/0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e",
params={
"pagina": 1,
"por_pagina": 50,
"filtro": "todos",
},
headers={"Authorization": f"Bearer {os.environ['CONSULTAPE_TOKEN']}"},
timeout=120,
)
datos = r.json()
print(datos["result"] if datos["success"] else f"Error {r.status_code}: {datos['message']}")Respuesta:
json
{
"success": true,
"message": "Operación exitosa",
"result": {
"lote": {
"id": "0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e",
"nombre_archivo": "comprobantes.xlsx",
"total": 248,
"procesados": 120,
"validos": 117,
"con_observacion": 3,
"porcentaje": 48,
"estado": "procesando",
"mensaje": null,
"created_at": "2026-10-04T15:20:11.000Z",
"terminado_at": null
},
"resultados": {
"items": [
{
"id": "0192f1c4-8b2f-7d4b-ae3f-4a5b6c7d8e9f",
"ruc_emisor": "20100070970",
"tipo": "01",
"tipo_texto": "FACTURA ELECTRONICA",
"serie": "F001",
"numero": "123",
"fecha_emision": "2024-01-15",
"monto": 118,
"estado_cp": "1",
"estado_cp_texto": "ACEPTADO",
"estado_ruc": "00",
"estado_ruc_texto": "ACTIVO",
"condicion_domicilio": "00",
"condicion_texto": "HABIDO",
"observaciones": [],
"procesado": true,
"exito": true,
"mensaje": null
},
{
"id": "0192f1c4-8b2f-7d4b-ae3f-4a5b6c7d8ea0",
"ruc_emisor": "20100070970",
"tipo": "03",
"tipo_texto": "BOLETA DE VENTA ELECTRONICA",
"serie": "B001",
"numero": "55",
"fecha_emision": "2024-01-16",
"monto": 45,
"estado_cp": null,
"estado_cp_texto": null,
"estado_ruc": null,
"estado_ruc_texto": null,
"condicion_domicilio": null,
"condicion_texto": null,
"observaciones": null,
"procesado": false,
"exito": false,
"mensaje": "Pendiente"
}
],
"total": 248,
"pagina": 1,
"por_pagina": 50
}
}
}procesado: false: la fila aún está en cola.procesado: trueyexito: false: SUNAT no respondió para esa fila;mensajeexplica el motivo.
Descargar resultados en Excel
GET /v1/cpe/validez-masiva/{id}/excel · Módulo cpe.validez_masiva
Descarga directa del archivo .xlsx (no usa la envoltura JSON). Funciona también con el lote en proceso: incluye lo validado hasta ese momento. Columnas: #, RUC emisor, Tipo, Serie, Número, Fecha emisión, Monto, Estado comprobante, Estado RUC, Condición domicilio, Observaciones, Mensaje.
| Parámetro | En | Tipo | Requerido | Descripción |
|---|---|---|---|---|
id | ruta | string (UUID) | Sí | Id del lote. |
bash
curl "https://api.consultape.pro/v1/cpe/validez-masiva/0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e/excel" \
-H "Authorization: Bearer $CONSULTAPE_TOKEN" \
-o "resultado-validez.xlsx"js
import { writeFile } from 'node:fs/promises';
const respuesta = await fetch('https://api.consultape.pro/v1/cpe/validez-masiva/0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e/excel', {
headers: {
Authorization: `Bearer ${process.env.CONSULTAPE_TOKEN}`,
},
});
if (respuesta.ok) {
await writeFile('resultado-validez.xlsx', Buffer.from(await respuesta.arrayBuffer()));
} else {
console.error((await respuesta.json()).message);
}php
<?php
$ch = curl_init('https://api.consultape.pro/v1/cpe/validez-masiva/0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e/excel');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CONSULTAPE_TOKEN')],
CURLOPT_TIMEOUT => 120,
]);
$cuerpo = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http === 200) {
file_put_contents('resultado-validez.xlsx', $cuerpo);
} else {
echo json_decode($cuerpo, true)['message'];
}python
import os
import requests
r = requests.get(
"https://api.consultape.pro/v1/cpe/validez-masiva/0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e/excel",
headers={"Authorization": f"Bearer {os.environ['CONSULTAPE_TOKEN']}"},
timeout=120,
)
if r.ok:
with open("resultado-validez.xlsx", "wb") as salida:
salida.write(r.content)
else:
print(r.json()["message"])Plantilla Excel
GET /v1/cpe/validez-masiva/plantilla · Módulo cpe.validez_masiva
Descarga plantilla-validez-masiva.xlsx (encabezados y dos filas de ejemplo). No usa la envoltura JSON.
bash
curl "https://api.consultape.pro/v1/cpe/validez-masiva/plantilla" \
-H "Authorization: Bearer $CONSULTAPE_TOKEN" \
-o "plantilla-validez-masiva.xlsx"js
import { writeFile } from 'node:fs/promises';
const respuesta = await fetch('https://api.consultape.pro/v1/cpe/validez-masiva/plantilla', {
headers: {
Authorization: `Bearer ${process.env.CONSULTAPE_TOKEN}`,
},
});
if (respuesta.ok) {
await writeFile('plantilla-validez-masiva.xlsx', Buffer.from(await respuesta.arrayBuffer()));
} else {
console.error((await respuesta.json()).message);
}php
<?php
$ch = curl_init('https://api.consultape.pro/v1/cpe/validez-masiva/plantilla');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CONSULTAPE_TOKEN')],
CURLOPT_TIMEOUT => 120,
]);
$cuerpo = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http === 200) {
file_put_contents('plantilla-validez-masiva.xlsx', $cuerpo);
} else {
echo json_decode($cuerpo, true)['message'];
}python
import os
import requests
r = requests.get(
"https://api.consultape.pro/v1/cpe/validez-masiva/plantilla",
headers={"Authorization": f"Bearer {os.environ['CONSULTAPE_TOKEN']}"},
timeout=120,
)
if r.ok:
with open("plantilla-validez-masiva.xlsx", "wb") as salida:
salida.write(r.content)
else:
print(r.json()["message"])Descargar CDR
POST /v1/cpe/cdr · Módulo cpe.cdr
Constancia de recepción (CDR) desde el web service de SUNAT. Solo para comprobantes emitidos por el RUC de la clave SOL: facturas (serie F…) y sus notas. Las boletas no están disponibles en este servicio de SUNAT.
| Parámetro | En | Tipo | Requerido | Descripción |
|---|---|---|---|---|
ruc | cuerpo | string | Sí, salvo con credencial_id | RUC emisor (dueño de la clave SOL). |
usuario_sol | cuerpo | string | Sí, salvo con credencial_id | Usuario SOL. |
clave_sol | cuerpo | string | Sí, salvo con credencial_id | Clave SOL. |
credencial_id | cuerpo | string (UUID) | No | Credencial guardada (reemplaza a los tres anteriores). |
tipo | cuerpo | string | Sí | 01, 03, 07 u 08. |
serie | cuerpo | string | Sí | 4 caracteres. |
numero | cuerpo | string | Sí | Número del comprobante. |
bash
curl -X POST "https://api.consultape.pro/v1/cpe/cdr" \
-H "Authorization: Bearer $CONSULTAPE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ruc": "20100070970", "usuario_sol": "MODDATOS", "clave_sol": "moddatos", "tipo": "01", "serie": "F001", "numero": "123"}'js
const respuesta = await fetch('https://api.consultape.pro/v1/cpe/cdr', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CONSULTAPE_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
ruc: '20100070970',
usuario_sol: 'MODDATOS',
clave_sol: 'moddatos',
tipo: '01',
serie: 'F001',
numero: '123',
}),
});
const datos = await respuesta.json();
if (datos.success) console.log(datos.result);
else console.error(respuesta.status, datos.message);php
<?php
$ch = curl_init('https://api.consultape.pro/v1/cpe/cdr');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CONSULTAPE_TOKEN'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'ruc' => '20100070970',
'usuario_sol' => 'MODDATOS',
'clave_sol' => 'moddatos',
'tipo' => '01',
'serie' => 'F001',
'numero' => '123',
]),
CURLOPT_TIMEOUT => 120,
]);
$cuerpo = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$datos = json_decode($cuerpo, true);
if ($datos['success']) {
print_r($datos['result']);
} else {
echo "Error $http: {$datos['message']}";
}python
import os
import requests
r = requests.post(
"https://api.consultape.pro/v1/cpe/cdr",
headers={"Authorization": f"Bearer {os.environ['CONSULTAPE_TOKEN']}"},
json={
"ruc": "20100070970",
"usuario_sol": "MODDATOS",
"clave_sol": "moddatos",
"tipo": "01",
"serie": "F001",
"numero": "123",
},
timeout=120,
)
datos = r.json()
print(datos["result"] if datos["success"] else f"Error {r.status_code}: {datos['message']}")Con una credencial guardada:
json
{ "credencial_id": "0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e", "tipo": "01", "serie": "F001", "numero": "123" }Respuesta:
json
{
"success": true,
"message": "La Factura numero F001-123, ha sido aceptada",
"result": {
"comprobante": "20100070970-01-F001-123",
"codigo": "0004",
"mensaje": "La constancia existe",
"respuesta_cdr": {
"codigo": "0",
"descripcion": "La Factura numero F001-123, ha sido aceptada"
},
"observaciones": [],
"archivo": {
"id": "0192f1c4-9c3a-7e5b-bf40-5b6c7d8e9fa1",
"nombre": "R-20100070970-01-F001-123.xml",
"url": "/v1/archivos/0192f1c4-9c3a-7e5b-bf40-5b6c7d8e9fa1"
}
}
}codigo/mensaje: estado del web service (0004= la constancia existe).respuesta_cdr.codigo:0aceptado;2000–3999rechazado;4000o más, aceptado con observaciones (verobservaciones).archivo: el XML del CDR firmado por SUNAT. Descárgalo con Archivos.
Fallas (HTTP 200, success: false; result.codigo trae el código de SUNAT cuando existe):
json
{ "success": false, "message": "SUNAT: Usuario o contraseña incorrectos (0102)", "result": { "codigo": "0102" } }json
{ "success": false, "message": "SUNAT: El comprobante de pago electrónico no existe (0011)", "result": { "codigo": "0011" } }Descargar XML
POST /v1/cpe/xml · Módulo cpe.xml
XML de un comprobante emitido (venta) o recibido (compra), desde SUNAT Operaciones en Línea. El primer inicio de sesión con la clave SOL tarda entre 15 y 40 segundos; luego la sesión se reutiliza unos 20 minutos.
| Parámetro | En | Tipo | Requerido | Descripción |
|---|---|---|---|---|
ruc | cuerpo | string | Sí, salvo con credencial_id | RUC dueño de la clave SOL. |
usuario_sol | cuerpo | string | Sí, salvo con credencial_id | Usuario SOL. |
clave_sol | cuerpo | string | Sí, salvo con credencial_id | Clave SOL. |
credencial_id | cuerpo | string (UUID) | No | Credencial guardada. |
proceso | cuerpo | string | Sí | venta (emitido por ruc) o compra (recibido por ruc). También acepta ventas, compras, 10, 11. |
ruc_emisor | cuerpo | string | En compras | RUC del proveedor. En ventas se ignora. |
tipo | cuerpo | string | No | 01 (por defecto), 03, 07, 08, 09 o 31. |
serie | cuerpo | string | Sí | 4 caracteres. |
numero | cuerpo | string | Sí | Número del comprobante. |
bash
curl -X POST "https://api.consultape.pro/v1/cpe/xml" \
-H "Authorization: Bearer $CONSULTAPE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"ruc": "20100070970", "usuario_sol": "MODDATOS", "clave_sol": "moddatos", "proceso": "compra", "ruc_emisor": "20600000001", "tipo": "01", "serie": "F001", "numero": "123"}'js
const respuesta = await fetch('https://api.consultape.pro/v1/cpe/xml', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CONSULTAPE_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
ruc: '20100070970',
usuario_sol: 'MODDATOS',
clave_sol: 'moddatos',
proceso: 'compra',
ruc_emisor: '20600000001',
tipo: '01',
serie: 'F001',
numero: '123',
}),
});
const datos = await respuesta.json();
if (datos.success) console.log(datos.result);
else console.error(respuesta.status, datos.message);php
<?php
$ch = curl_init('https://api.consultape.pro/v1/cpe/xml');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CONSULTAPE_TOKEN'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'ruc' => '20100070970',
'usuario_sol' => 'MODDATOS',
'clave_sol' => 'moddatos',
'proceso' => 'compra',
'ruc_emisor' => '20600000001',
'tipo' => '01',
'serie' => 'F001',
'numero' => '123',
]),
CURLOPT_TIMEOUT => 120,
]);
$cuerpo = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$datos = json_decode($cuerpo, true);
if ($datos['success']) {
print_r($datos['result']);
} else {
echo "Error $http: {$datos['message']}";
}python
import os
import requests
r = requests.post(
"https://api.consultape.pro/v1/cpe/xml",
headers={"Authorization": f"Bearer {os.environ['CONSULTAPE_TOKEN']}"},
json={
"ruc": "20100070970",
"usuario_sol": "MODDATOS",
"clave_sol": "moddatos",
"proceso": "compra",
"ruc_emisor": "20600000001",
"tipo": "01",
"serie": "F001",
"numero": "123",
},
timeout=120,
)
datos = r.json()
print(datos["result"] if datos["success"] else f"Error {r.status_code}: {datos['message']}")Respuesta:
json
{
"success": true,
"message": "XML descargado",
"result": {
"comprobante": "20600000001-01-F001-123",
"proceso": "compra",
"fuente": "consultape.pro",
"resumen": {
"tipo": "01",
"tipo_texto": "FACTURA ELECTRONICA",
"serie": "F001",
"numero": "00000123",
"fecha_emision": "2024-01-15",
"hora_emision": "10:20:30",
"moneda": "PEN",
"emisor": { "ruc": "20600000001", "razon_social": "PROVEEDOR SAC" },
"cliente": { "tipo_documento": "6", "numero": "20100070970", "nombre": "MI EMPRESA SAC" },
"gravado": 100,
"exonerado": 0,
"inafecto": 0,
"igv": 18,
"total": 118,
"items": [
{
"cantidad": 1,
"unidad": "NIU",
"descripcion": "Servicio",
"valor_unitario": 100,
"precio_unitario": 118,
"igv": 18,
"total": 118
}
]
},
"archivo": {
"id": "0192f1c4-9c3a-7e5b-bf40-5b6c7d8e9fa2",
"nombre": "20600000001-01-F001-123.xml",
"url": "/v1/archivos/0192f1c4-9c3a-7e5b-bf40-5b6c7d8e9fa2"
}
}
}resumen: datos principales leídos del XML, listos para registrar en tu sistema.fuente: siempreconsultape.pro.
Fallas (HTTP 200, success: false):
SUNAT: Usuario o contraseña incorrectosEl usuario SOL no tiene permiso a: Nueva consulta de comprobantes de pago. Habilítalo en SUNAT Operaciones en Línea.SUNAT no encontró el comprobante. Verifica RUC, serie, número y si es venta o compra.SUNAT no respondió. Intenta nuevamente en unos minutos.
Descargar PDF
POST /v1/cpe/pdf · Módulo cpe.pdf
Representación impresa (PDF) del comprobante. Mismos parámetros que Descargar XML.
bash
curl -X POST "https://api.consultape.pro/v1/cpe/pdf" \
-H "Authorization: Bearer $CONSULTAPE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"credencial_id": "0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e", "proceso": "venta", "tipo": "01", "serie": "F001", "numero": "123"}'js
const respuesta = await fetch('https://api.consultape.pro/v1/cpe/pdf', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CONSULTAPE_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
credencial_id: '0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e',
proceso: 'venta',
tipo: '01',
serie: 'F001',
numero: '123',
}),
});
const datos = await respuesta.json();
if (datos.success) console.log(datos.result);
else console.error(respuesta.status, datos.message);php
<?php
$ch = curl_init('https://api.consultape.pro/v1/cpe/pdf');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CONSULTAPE_TOKEN'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'credencial_id' => '0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e',
'proceso' => 'venta',
'tipo' => '01',
'serie' => 'F001',
'numero' => '123',
]),
CURLOPT_TIMEOUT => 120,
]);
$cuerpo = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$datos = json_decode($cuerpo, true);
if ($datos['success']) {
print_r($datos['result']);
} else {
echo "Error $http: {$datos['message']}";
}python
import os
import requests
r = requests.post(
"https://api.consultape.pro/v1/cpe/pdf",
headers={"Authorization": f"Bearer {os.environ['CONSULTAPE_TOKEN']}"},
json={
"credencial_id": "0192f1c4-7a1e-7c3a-9d2e-3f4b5a6c7d8e",
"proceso": "venta",
"tipo": "01",
"serie": "F001",
"numero": "123",
},
timeout=120,
)
datos = r.json()
print(datos["result"] if datos["success"] else f"Error {r.status_code}: {datos['message']}")Respuesta:
json
{
"success": true,
"message": "PDF descargado",
"result": {
"comprobante": "20100070970-01-F001-123",
"proceso": "venta",
"fuente": "consultape.pro",
"archivo": {
"id": "0192f1c4-9c3a-7e5b-bf40-5b6c7d8e9fa3",
"nombre": "20100070970-01-F001-123.pdf",
"url": "/v1/archivos/0192f1c4-9c3a-7e5b-bf40-5b6c7d8e9fa3"
}
}
}fuente: siempre consultape.pro. Si SUNAT no tiene el PDF, ConsultaPe genera la representación impresa a partir del XML.
PDF desde un XML
POST /v1/cpe/pdf-desde-xml · Módulo cpe.pdf
Genera la representación impresa (A4, con código QR) a partir de un XML UBL 2.1 que ya tienes. No necesita clave SOL.
Cuerpo multipart/form-data:
| Parámetro | En | Tipo | Requerido | Descripción |
|---|---|---|---|---|
archivo | formulario | archivo | Sí | XML UBL 2.1 (factura, boleta, nota de crédito o débito) o el .zip que entrega SUNAT. Máximo 2 MB. |
bash
curl -X POST "https://api.consultape.pro/v1/cpe/pdf-desde-xml" \
-H "Authorization: Bearer $CONSULTAPE_TOKEN" \
-F "[email protected]"js
import { readFile } from 'node:fs/promises';
const formulario = new FormData();
formulario.append('archivo', new Blob([await readFile('20600000001-01-F001-00000123.xml')]), '20600000001-01-F001-00000123.xml');
const respuesta = await fetch('https://api.consultape.pro/v1/cpe/pdf-desde-xml', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CONSULTAPE_TOKEN}`,
},
body: formulario,
});
const datos = await respuesta.json();
if (datos.success) console.log(datos.result);
else console.error(respuesta.status, datos.message);php
<?php
$ch = curl_init('https://api.consultape.pro/v1/cpe/pdf-desde-xml');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('CONSULTAPE_TOKEN')],
CURLOPT_POSTFIELDS => ['archivo' => new CURLFile('20600000001-01-F001-00000123.xml')],
CURLOPT_TIMEOUT => 120,
]);
$cuerpo = curl_exec($ch);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$datos = json_decode($cuerpo, true);
if ($datos['success']) {
print_r($datos['result']);
} else {
echo "Error $http: {$datos['message']}";
}python
import os
import requests
with open("20600000001-01-F001-00000123.xml", "rb") as f:
r = requests.post(
"https://api.consultape.pro/v1/cpe/pdf-desde-xml",
headers={"Authorization": f"Bearer {os.environ['CONSULTAPE_TOKEN']}"},
files={"archivo": f},
timeout=120,
)
datos = r.json()
print(datos["result"] if datos["success"] else f"Error {r.status_code}: {datos['message']}")Respuesta:
json
{
"success": true,
"message": "PDF generado",
"result": {
"comprobante": "20600000001-01-F001-00000123",
"tipo_texto": "FACTURA ELECTRONICA",
"resumen": {
"tipo": "01",
"tipo_texto": "FACTURA ELECTRONICA",
"serie": "F001",
"numero": "00000123",
"fecha_emision": "2024-01-15",
"hora_emision": "10:20:30",
"moneda": "PEN",
"emisor": { "ruc": "20600000001", "razon_social": "PROVEEDOR SAC" },
"cliente": { "tipo_documento": "6", "numero": "20100070970", "nombre": "MI EMPRESA SAC" },
"gravado": 100,
"exonerado": 0,
"inafecto": 0,
"igv": 18,
"total": 118,
"items": []
},
"archivo": {
"id": "0192f1c4-9c3a-7e5b-bf40-5b6c7d8e9fa4",
"nombre": "20600000001-01-F001-00000123.pdf",
"url": "/v1/archivos/0192f1c4-9c3a-7e5b-bf40-5b6c7d8e9fa4"
}
}
}Errores (HTTP 400):
El archivo debe ser un XML UBL o un ZIP que lo contenga.El XML no es un comprobante UBL válido (Invoice, CreditNote o DebitNote).