Dar de baja
Da de baja un comprobante ya aceptado por SUNAT. Manda el motivo; el resto lo ponemos nosotros.
Autenticación: token Bearer de empresa (cpe:sign).
Consideraciones
- Manda solo el
motivo. De elegir el documento que SUNAT pide en cada caso —comunicación de baja para facturas, resumen para boletas, reversión para retenciones y percepciones—, numerarlo y firmarlo nos encargamos nosotros. - La respuesta es la baja, no el comprobante original: un documento aparte con su propio
external_id, XML y CDR, que se consulta como cualquier otro. - El comprobante original no cambia: conserva su estado y su CDR. SUNAT lo aceptó, y esa aceptación siguió siendo cierta.
- Queda marcado como anulado cuando SUNAT acepta la baja, no al pedirla. Una baja fuera de plazo se rechaza y el comprobante sigue vivo.
- La baja siempre va por ticket, aunque el comprobante original recibiera su CDR en el acto. Es cosa de SUNAT, y por eso tarda más.
- Cada baja es un documento firmado, así que consume una firma.
- Las guías de remisión se dan de baja por el servicio REST de SUNAT y todavía no lo cubrimos: responden
422.
Una llamada
curl -X POST https://api.xmlperu.dev/v1/cpe/$EXTERNAL_ID/void \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"reason": "Error en el monto"}'
No hace falta saber si tu comprobante se anula con una comunicación de baja o con un resumen, ni llevar la cuenta de los correlativos diarios de esos documentos. Eso es mecánica de SUNAT y la absorbemos.
Dos comprobantes, dos identificadores
La baja no es un estado del comprobante: es un documento aparte.
# ¿Aceptó SUNAT la baja?
curl https://api.xmlperu.dev/v1/cpe/$ID_DE_LA_BAJA -H "Authorization: Bearer $TOKEN"
# El original: sigue Aceptado, con su CDR
curl https://api.xmlperu.dev/v1/cpe/$EXTERNAL_ID -H "Authorization: Bearer $TOKEN"
Que la baja pueda ser rechazada es el motivo de que haga falta consultarla: una baja fuera de plazo o mal referenciada no anula nada, y el comprobante sigue declarado. Por eso la marca de anulado aparece después del CDR de la baja y no antes.
Qué se puede dar de baja
| Comprobante | Se da de baja con |
|---|---|
Factura 01 |
Comunicación de baja |
Boleta 03 |
Resumen con condición de anulación |
Notas 07 · 08 |
Lo que corresponda al comprobante al que afectan |
Retención 20 · Percepción 40 |
Reversión |
Guías 09 · 31 |
Todavía no — 422 |
Las notas heredan: una nota de boleta se anula por resumen y una de factura por comunicación de baja. No hay nada que elegir ni que configurar.
Headers
| Name | Type | Description |
|---|---|---|
| Accept | string | application/json |
| Content-Type | string | application/json |
| Authorization | string | Bearer <token>. Genéralo desde tu panel, en Tokens de API. |
Parámetros de URL
| Name | Type | Description |
|---|---|---|
| external_id* | string | Identificador del comprobante que se da de baja. |
Body
| Name | Type | Description |
|---|---|---|
| reason* | string | Por qué se da de baja. SUNAT lo exige. Entre 3 y 250 caracteres. |
Ejemplo de solicitud
curl -X POST https://api.xmlperu.dev/v1/cpe/9c2f1b7e-0000-0000-0000-000000000000/void \
-H "Authorization: Bearer $TOKEN_EMPRESA" \
-H "Accept: application/json"<?php
$token_empresa = 'pega-aqui-tu-token';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.xmlperu.dev/v1/cpe/9c2f1b7e-0000-0000-0000-000000000000/void');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $token_empresa,
'Accept: application/json',
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);const TOKEN_EMPRESA = 'pega-aqui-tu-token';
const res = await fetch('https://api.xmlperu.dev/v1/cpe/9c2f1b7e-0000-0000-0000-000000000000/void', {
method: 'POST',
headers: {
Authorization: `Bearer ${TOKEN_EMPRESA}`,
Accept: 'application/json',
},
});
const data = await res.json();import requests
TOKEN_EMPRESA = "pega-aqui-tu-token"
headers = {
"Authorization": f"Bearer {TOKEN_EMPRESA}",
"Accept": "application/json",
}
res = requests.post("https://api.xmlperu.dev/v1/cpe/9c2f1b7e-0000-0000-0000-000000000000/void", headers=headers)
data = res.json()Respuesta
{
"success": true,
"status": "queued",
"message": "Baja firmada. El envío a SUNAT quedó encolado.",
"external_id": "3f8a1c2e-…",
"filename": "20123456789-RA-20260829-1",
"hash": "…",
"xml": "PD94bWwg…",
"voids": "9c2f1b7e-…"
}{
"success": false,
"message": "SUNAT todavía no aceptó el comprobante: no hay nada que dar de baja. Consulta su estado."
}{
"success": false,
"message": "Venció el plazo para dar de baja este comprobante (7 días desde la emisión). Emite una nota de crédito."
}