Anular DTE
El API ofrece dos endpoints de anulación, según el tipo de documento:
POST /invalidate/{id_or_ref}— para Factura (01), CCF (03), Exportación (11), y Nota de Crédito (05).POST /invalidate/suex/{id_or_ref}— específico para Sujeto Excluido (14).
Son rutas distintas porque SUEX vive en un modelo diferente (PurchaseHeader) y requiere endpoints dedicados.
Ventanas de anulación del MH
El MH permite invalidación directa solo dentro de ciertas ventanas temporales:
| Tipo | Ventana de invalidación directa | Qué pasa fuera de ventana |
|---|---|---|
| Factura (01) | 24 horas desde emisión | MH rechaza la invalidación. |
| CCF (03) | 3 meses desde emisión | El API genera automáticamente una Nota de Crédito para anular el CCF. |
| Exportación (11) | Variable según normativa MH | Depende del caso; MH puede rechazar. |
| Nota de Crédito (05) | Se puede anular la NC en 24 h | Fuera de ventana: no recuperable. |
| SUEX (14) | 24 horas | MH rechaza. |
Si llamas /invalidate/{ccf_id} y el CCF tiene más de 3 meses, el API no falla. Detecta la situación, crea una NC que ajusta el CCF completo, y te devuelve en el response created_credit_memo: true con el UUID y control number de la NC generada. Desde tu lado la única acción fue un POST a /invalidate — el API maneja el resto.
Anular Factura, CCF, Exportación o NC
Detalles técnicos
| Método | POST |
| URL | https://ocote.io/api/connect/invalidate/{id_or_ref} |
| Body | No lleva body. |
| Autenticación | Header Authorization: Bearer odt_... |
El {id_or_ref} en la URL puede ser el UUID del documento o tu external_ref.
Request
No requiere body. Todo está en la URL:
curl -X POST https://ocote.io/api/connect/invalidate/VENTA-2026-0042 \
-H "Authorization: Bearer odt_xxx"
const { data } = await axios.post(
'https://ocote.io/api/connect/invalidate/VENTA-2026-0042',
null,
{ headers: { Authorization: `Bearer ${process.env.OCOTE_API_KEY}` } }
);
r = requests.post(
f"https://ocote.io/api/connect/invalidate/VENTA-2026-0042",
headers={"Authorization": f"Bearer {API_KEY}"},
)
Response
| Campo | Tipo | Descripción |
|---|---|---|
success | bool | true si la operación se registró en Ocote (incluye contingencia). |
message | string | Mensaje descriptivo del estado. |
document_id | string (UUID) | ID del documento afectado. |
invalidated | bool | true si el API intentó invalidar. Combinado con dte_success dice si quedó firmado. |
created_credit_memo | bool | true si se generó una NC automática (caso CCF fuera de ventana). |
credit_memo_id | string | UUID de la NC generada (vacío si no se generó). |
credit_memo_control_number | string | Correlativo de la NC (DTE-05-...). |
dte_success | bool | MH aceptó la invalidación. |
contingency | bool | MH no respondió; la invalidación se revalidará. |
rejected | bool | MH rechazó la invalidación. |
dte_state, dte_message, observaciones, codigo_msg | — | Diagnóstico si hubo rechazo. Ver Respuestas y estados. |
Ejemplos de response
CCF dentro de ventana, anulación directa exitosa:
{
"success": true,
"message": "Documento invalidado",
"document_id": "a1b2c3d4-...",
"invalidated": true,
"created_credit_memo": false,
"credit_memo_id": "",
"credit_memo_control_number": "",
"dte_success": true,
"contingency": false,
"rejected": false
}
CCF fuera de ventana, NC generada automáticamente:
{
"success": true,
"message": "CCF fuera de ventana. Nota de Credito generada automaticamente.",
"document_id": "a1b2c3d4-...",
"invalidated": true,
"created_credit_memo": true,
"credit_memo_id": "b2c3d4e5-...",
"credit_memo_control_number": "DTE-05-M001P002-000000000000007",
"dte_success": true,
"contingency": false,
"rejected": false
}
Ya estaba invalidado (idempotencia):
{
"success": true,
"message": "Documento ya invalidado",
"document_id": "a1b2c3d4-...",
"invalidated": true,
"created_credit_memo": false,
"dte_success": true,
"contingency": false,
"rejected": false
}
Llamar /invalidate sobre un documento ya invalidado es seguro: devuelve el estado actual sin efectos secundarios. Ver Retry e idempotencia > Invalidación.
Anular Sujeto Excluido
Detalles técnicos
| Método | POST |
| URL | https://ocote.io/api/connect/invalidate/suex/{id_or_ref} |
| Body | No lleva body. |
| Autenticación | Header Authorization: Bearer odt_... |
curl -X POST https://ocote.io/api/connect/invalidate/suex/SUEX-2026-0015 \
-H "Authorization: Bearer odt_xxx"
El response tiene la misma estructura pero nunca se genera NC automática — el mecanismo de NC es exclusivo de CCF. Si el SUEX está fuera de ventana, el MH rechaza y recibes rejected: true.
Errores de validación
| HTTP | Mensaje | Causa |
|---|---|---|
| 404 | Documento no encontrado | El id_or_ref no existe en tu empresa. |
| 400 | Documento no puede ser invalidado | El documento está en un estado incompatible (no procesado, ya fue NC, etc.). |
| 400 | Mensaje específico del MH | Ver observaciones en el response para el detalle. |
Ver también
- Nota de Crédito (05) — cuando necesitas control explícito sobre líneas ajustadas.
- Retry e idempotencia — comportamiento en reintentos de invalidación.
- Respuestas y estados — semántica completa de flags.
- Consultar estado — endpoint para verificar estado post-invalidación.