Skip to main content

¿Qué es el CDR?

El CDR (Constancia de Recepción) es la respuesta oficial de SUNAT confirmando que un comprobante electrónico fue recibido y validado. Formato: Archivo ZIP que contiene un XML de respuesta Nombre del archivo:
R-{RUC}-{TipoDoc}-{Serie}-{Numero}.zip

Ejemplo:
R-20612706702-01-F001-00000045.zip
Contenido del CDR:
  • XML de respuesta: Con código y mensaje de SUNAT
  • Firma digital de SUNAT: Valida la autenticidad del CDR
  • Fecha y hora de procesamiento
  • Observaciones (si las hay)

Ubicación de los CDR

Los CDR se almacenan en:
storage/app/sunat/cdr/{ruc}/
Ejemplo de estructura:
storage/app/sunat/cdr/20612706702/
├── R-20612706702-01-F001-00000045.zip  (CDR de factura)
├── R-20612706702-03-B001-00000123.zip  (CDR de boleta individual - raro)
├── R-20612706702-07-FC01-00000012.zip  (CDR de nota de crédito)
├── R-20612706702-09-T001-00000003.zip  (CDR de guía de remisión)
└── R-ticket-1234567890.zip             (CDR de resumen diario/comunicación de baja)

Consulta de CDR desde la UI

1

Acceder al listado de comprobantes

Vaya a Facturación → Ventas (o el módulo correspondiente).En la tabla, identifique los comprobantes enviados:
  • Badge verde “Aceptado” indica que hay CDR disponible
  • Badge rojo “Rechazado” también genera CDR (con el detalle del rechazo)
2

Descargar CDR

Haga clic en el botón Descargar CDR (💾) de la fila del comprobante.El navegador descargará el archivo ZIP.URL directa:
/storage/sunat/cdr/{ruc}/R-{nombre}.zip
3

Extraer y leer el XML

Descomprima el ZIP. Contendrá un archivo XML:
R-20612706702-01-F001-00000045.xml
Abra el XML con un editor de texto o navegador.

Estructura del XML del CDR

<?xml version="1.0" encoding="UTF-8"?>
<ApplicationResponse xmlns="urn:oasis:names:specification:ubl:schema:xsd:ApplicationResponse-2"
                     xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
                     xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2">
  
  <ext:UBLExtensions>
    <ext:UBLExtension>
      <ext:ExtensionContent>
        <!-- Firma digital de SUNAT -->
        <ds:Signature Id="signatureKG">
          <!-- ... certificado y firma ... -->
        </ds:Signature>
      </ext:ExtensionContent>
    </ext:UBLExtension>
  </ext:UBLExtensions>
  
  <cbc:UBLVersionID>2.0</cbc:UBLVersionID>
  <cbc:CustomizationID>1.0</cbc:CustomizationID>
  <cbc:ID>20612706702-01-F001-00000045</cbc:ID>
  <cbc:IssueDate>2026-03-06</cbc:IssueDate>
  <cbc:IssueTime>14:30:45</cbc:IssueTime>
  
  <cac:DocumentResponse>
    <cac:Response>
      <cbc:ResponseCode>0</cbc:ResponseCode>
      <cbc:Description>La Factura numero F001-00000045, ha sido aceptada</cbc:Description>
    </cac:Response>
    
    <cac:DocumentReference>
      <cbc:ID>F001-00000045</cbc:ID>
    </cac:DocumentReference>
  </cac:DocumentResponse>
  
</ApplicationResponse>

Campos Clave

CampoDescripciónEjemplo
<cbc:ID>Identificador del documento20612706702-01-F001-00000045
<cbc:IssueDate>Fecha de respuesta de SUNAT2026-03-06
<cbc:IssueTime>Hora de respuesta de SUNAT14:30:45
<cbc:ResponseCode>Código de respuesta0 (aceptado)
<cbc:Description>Mensaje descriptivo”La Factura… ha sido aceptada”
<ds:Signature>Firma digital de SUNAT(contenido de certificado)

Códigos de Respuesta en el CDR

Códigos Exitosos

CódigoSignificadoAcción
0AceptadoComprobante válido, sin observaciones
0001Aceptado con observacionesVálido pero con advertencias (ej: RUC de cliente no existe en SUNAT)

Códigos de Error

Ver la guía completa: Solucionar Errores SUNAT Errores comunes en CDR:
  • 2010: El RUC del cliente no existe
  • 2335: El certificado no es válido
  • 2800: El comprobante ya fue informado anteriormente
  • 4000: El formato del XML es inválido

Consulta Programática del CDR

Endpoint: Descargar CDR

GET /api/ventas/{id_venta}/cdr
Authorization: Bearer {token}
Respuesta (si existe CDR):
{
  "success": true,
  "data": {
    "cdr_url": "sunat/cdr/20612706702/R-20612706702-01-F001-00000045.zip",
    "codigo_sunat": "0",
    "mensaje_sunat": "La Factura numero F001-00000045, ha sido aceptada",
    "fecha_respuesta": "2026-03-06T14:30:45",
    "download_url": "/storage/sunat/cdr/20612706702/R-20612706702-01-F001-00000045.zip"
  }
}
Respuesta (si NO existe CDR):
{
  "success": false,
  "message": "CDR no disponible. El comprobante no ha sido enviado a SUNAT o aún está en proceso."
}

Leer el contenido del CDR

use Illuminate\Support\Facades\Storage;

$venta = Venta::find($idVenta);

if (!$venta->cdr_url) {
    return response()->json(['error' => 'CDR no disponible'], 404);
}

// Leer el ZIP
$zipPath = storage_path("app/{$venta->cdr_url}");

if (!file_exists($zipPath)) {
    return response()->json(['error' => 'Archivo CDR no encontrado'], 404);
}

// Extraer el XML del ZIP
$zip = new \ZipArchive();
if ($zip->open($zipPath) === true) {
    $xmlContent = $zip->getFromIndex(0);  // Primer archivo del ZIP
    $zip->close();
    
    // Parsear el XML
    $xml = simplexml_load_string($xmlContent);
    $namespaces = $xml->getNamespaces(true);
    $xml->registerXPathNamespace('cbc', $namespaces['cbc']);
    $xml->registerXPathNamespace('cac', $namespaces['cac']);
    
    $responseCode = (string) $xml->xpath('//cbc:ResponseCode')[0];
    $description = (string) $xml->xpath('//cbc:Description')[0];
    
    return response()->json([
        'codigo' => $responseCode,
        'mensaje' => $description,
        'xml_completo' => $xmlContent,
    ]);
}

return response()->json(['error' => 'No se pudo abrir el ZIP'], 500);

Validación de la Firma del CDR

El CDR viene firmado digitalmente por SUNAT. Para validar la firma:

1. Extraer el certificado de SUNAT

# Descomprimir el CDR
unzip R-20612706702-01-F001-00000045.zip

# Extraer certificado del XML (requiere herramientas XML)
xmlsec1 --verify --id-attr:ID Signature R-20612706702-01-F001-00000045.xml

2. Verificar con OpenSSL

# Extraer el certificado de SUNAT del XML
openssl x509 -in sunat-cert.pem -noout -text

# Verificar que el emisor sea SUNAT
# Issuer: C=PE, O=SUNAT, CN=...
En producción: La validación de firma se hace automáticamente al recibir el CDR. Si el CDR fue guardado exitosamente en el sistema, la firma ya fue validada por Greenter.

CDR de Documentos Asíncronos

Resumen Diario de Boletas

El CDR se genera después de consultar el ticket:
Archivo:
R-ticket-1234567890.zip

Contenido:
R-20612706702-RC-20260306-001.xml
El XML contiene la respuesta para TODO el lote de boletas.

Guías de Remisión

El CDR de guías viene en base64 desde la API REST:
// En SunatService::consultarTicketGuia() (línea 882-890)
$status = $cpeApi->consultarEnvio($ticket);

if ($status->getCodRespuesta() === '0') {
    $cdrBase64 = $status->getArcCdr();
    $cdrContent = base64_decode($cdrBase64);
    
    $cdrDir = storage_path("app/sunat/cdr/{$ruc}");
    file_put_contents("{$cdrDir}/R-{$nombreXml}.zip", $cdrContent);
}

Reenvío de CDR a Correo

Algunos clientes solicitan el CDR por correo. Puede implementar:
use Illuminate\Support\Facades\Mail;
use App\Mail\CDREmail;

public function enviarCDRPorCorreo(Venta $venta, string $emailCliente)
{
    if (!$venta->cdr_url) {
        throw new \Exception('CDR no disponible');
    }
    
    $cdrPath = storage_path("app/{$venta->cdr_url}");
    $xmlPath = storage_path("app/{$venta->xml_url}");
    
    Mail::to($emailCliente)->send(new CDREmail($venta, [
        'cdr' => $cdrPath,
        'xml' => $xmlPath,
    ]));
}
En app/Mail/CDREmail.php:
public function build()
{
    return $this->subject("Comprobante Electrónico {$this->venta->numero_completo}")
                ->view('emails.cdr')
                ->attach($this->attachments['xml'], [
                    'as' => $this->venta->nombre_xml . '.xml',
                    'mime' => 'application/xml',
                ])
                ->attach($this->attachments['cdr'], [
                    'as' => 'R-' . $this->venta->nombre_xml . '.zip',
                    'mime' => 'application/zip',
                ]);
}

Verificación de Comprobantes en SUNAT

Los clientes pueden verificar el comprobante en: URL de verificación:
https://www.sunat.gob.pe/ol-ti-itconsvalicpe/ConsValiCpe.htm
Datos necesarios:
  • RUC del emisor: 20612706702
  • Tipo de comprobante: Factura (01)
  • Serie: F001
  • Número: 00000045
  • Fecha de emisión: 06/03/2026
  • Monto total: 550.00
SUNAT responde si el comprobante existe y su estado.

Generación de QR con CDR

El QR del comprobante debe incluir datos del CDR:
use chillerlan\QRCode\QRCode;

$qrData = implode('|', [
    $empresa->ruc,
    $venta->tipoDocumento->cod_sunat,
    $venta->serie,
    $venta->numero,
    $venta->igv,
    $venta->total,
    $venta->fecha_emision->format('Y-m-d'),
    $venta->cliente->tipo_doc,
    $venta->cliente->documento,
    $venta->hash_cpe,  // Hash del XML firmado
]);

$qrImage = (new QRCode)->render($qrData);
El QR permite verificación instantánea con apps de SUNAT.

Solución de Problemas

Causa: El archivo no se guardó correctamente o la ruta es incorrecta.Solución:
  1. Verifique en storage:
    ls -l storage/app/sunat/cdr/{ruc}/
    
  2. Verifique el campo cdr_url en la base de datos:
    SELECT cdr_url FROM ventas WHERE id_venta = 45;
    
  3. Si el campo está vacío pero el comprobante fue aceptado, reenvíe para obtener el CDR nuevamente.
Causa: El archivo CDR fue eliminado o movido.Solución:
  1. Reenvíe el comprobante a SUNAT:
    POST /api/ventas/{id}/enviar-sunat
    
    SUNAT devolverá el CDR nuevamente (si el comprobante ya fue aceptado, responderá con el CDR original).
  2. Verifique permisos de storage:
    chmod -R 755 storage/app/sunat/cdr/
    
Si el archivo local se perdió:
  1. Reenvío: SUNAT devuelve el CDR original al reenviar un comprobante ya aceptado
  2. Consulta en SUNAT Operaciones en Línea:
    • Ingrese con Clave SOL
    • Vaya a Consultas → Comprobantes Electrónicos
    • Busque el comprobante y descargue el CDR
El comprobante fue aceptado pero con advertencias.Observaciones comunes:
  • “El RUC del cliente no existe en el padrón”
  • “El cliente no está habilitado para emitir comprobantes”
Estas NO invalidan el comprobante, pero recomendamos corregir los datos para futuros envíos.

Almacenamiento y Respaldo

Obligación tributaria: Los CDR deben conservarse por 5 años junto con los XML. Es responsabilidad del contribuyente mantener copias seguras.
Recomendaciones:
  1. Backup diario de storage/app/sunat/
  2. Backup en la nube (S3, Google Drive, etc.)
  3. Compresión mensual de archivos antiguos
  4. Verificación periódica de integridad de archivos

Próximos Pasos

Build docs developers (and LLMs) love