Saltar al contenido principal

Nota de Crédito (05)

La Nota de Crédito (tipo 05) se emite para ajustar un CCF (tipo 03) ya emitido. Se usa típicamente para:

  • Devoluciones de mercadería.
  • Correcciones de precio o cantidad posteriores a la emisión.
  • Anulación de un CCF que ya salió de la ventana de invalidación directa.
  • Descuentos aplicados después de la facturación.

La NC no aplica a Facturas (01), Exportaciones (11), ni SUEX (14). Para esos tipos se usa Anulación directa.

/credit-memo vs /invalidate — cuándo usar cada uno

Cuando necesitas revertir un CCF tienes dos caminos:

SituaciónEndpointQué hace
Ajuste parcial (p.ej. devolución de 2 items de 10)POST /credit-memo con linesGenera NC parcial, deja el CCF vigente.
Ajuste total intencionalPOST /credit-memo con full_adjustment: trueGenera NC completa, marca el CCF como invalidado.
Anular CCF completo dentro de ventana de invalidaciónPOST /invalidate/{id}Anulación directa en MH. Más simple.
Anular CCF completo fuera de ventana de invalidaciónPOST /invalidate/{id}El API crea automáticamente una NC porque el MH ya no permite anulación directa.

Si solo quieres anular un CCF completo, usa /invalidate — el API decide solo si hacer anulación directa o generar una NC automática. Usa /credit-memo cuando necesitas control explícito sobre las líneas ajustadas.

Detalles técnicos

MétodoPOST
URLhttps://ocote.io/api/connect/credit-memo
Content-Typeapplication/json
AutenticaciónHeader Authorization: Bearer odt_...

Request

Campos

CampoTipoRequeridoDescripción
document_idstringUUID o external_ref del CCF a ajustar.
full_adjustmentboolNo (default false)Si true, genera NC completa (clona todas las líneas del CCF) e invalida el CCF.
linesarrayNoLíneas específicas a ajustar. Solo válido con full_adjustment: false. Si no envías líneas y full_adjustment: false, el API clona todas las del CCF pero no invalida.
external_refstringNoTu identificador idempotente para la NC.

Líneas (lines)

CampoTipoRequeridoDescripción
descriptionstringDescripción del ítem ajustado (típicamente igual al del CCF original).
quantityfloatCantidad a ajustar.
unit_pricefloatPrecio unitario con IVA incluido.
discount_percentagefloatNo (default 0)Descuento.

Los tres modos de emisión

Modo 1: Ajuste completo explícito (full_adjustment: true)

El API copia todas las líneas del CCF original a la NC y marca el CCF como invalidado. Equivale a una anulación pero genera un documento fiscal explícito de ajuste.

{
"document_id": "CCF-ENLACES-001",
"full_adjustment": true,
"external_ref": "NC-DEV-TOTAL-001"
}

Úsalo cuando quieres un documento de anulación formal con todas las líneas visibles.

Modo 2: Ajuste parcial (full_adjustment: false + lines)

Solo ajustas lo que especificas en lines. El CCF queda vigente pero con monto ajustado.

{
"document_id": "CCF-ENLACES-001",
"full_adjustment": false,
"lines": [
{
"description": "Laptop Dell XPS devuelta",
"quantity": 1,
"unit_price": 1200.00
}
],
"external_ref": "NC-DEV-PARCIAL-001"
}

Úsalo para devoluciones reales (regresó 1 item de 10) o descuentos post-facturación.

Modo 3: Clonación sin invalidar (sin lines, full_adjustment: false)

El API clona todas las líneas del CCF pero no lo invalida. Es útil para "anotar" un ajuste completo sin anular fiscalmente el CCF.

{
"document_id": "CCF-ENLACES-001",
"external_ref": "NC-AJUSTE-001"
}

Es el modo menos común. Si necesitas anular completamente, prefiere Modo 1 o el endpoint /invalidate.

Validaciones

El API valida sobre el CCF antes de procesar:

ValidaciónHTTPMensaje
CCF no existe o no es tuyo404Documento no encontrado
Documento referenciado no es CCF400Solo se pueden emitir Notas de Credito sobre CCF (tipo 03)
CCF ya invalidado400Este CCF ya fue invalidado
CCF ya completamente ajustado400Este CCF ya fue completamente ajustado
CCF con más de 90 días hábiles400Este CCF tiene mas de 90 dias y no puede ser ajustado
Ventana de 90 días hábiles

La NC directa vía /credit-memo solo aplica mientras el CCF tiene menos de 90 días hábiles desde su emisión. Después de eso, el API rechaza el ajuste y debes usar otros mecanismos contables. Si tu intención era simplemente anular un CCF antiguo completo, usa POST /invalidate/{ccf_id} — ese endpoint maneja automáticamente el caso de fuera de ventana generando la NC equivalente.

Response

Además de los flags estándar (Respuestas y estados), la NC devuelve campos específicos:

CampoTipoDescripción
document_idstring (UUID)ID de la NC creada.
external_refstringEl que enviaste (o autogenerado).
control_numberstringCorrelativo de la NC (DTE-05-...).
generation_codestringCódigo de generación MH.
reception_stampstringSello MH de la NC.
ccf_control_numberstringCorrelativo del CCF ajustado.
ccf_adjusted_amountfloatMonto total ajustado (suma de líneas de la NC).
ccf_fully_adjustedbooltrue si el CCF quedó completamente ajustado tras esta NC.
dteobjectSchema firmado completo de la NC (solo si dte_success: true).

Ejemplo: devolución parcial

Escenario: emitiste un CCF por tres productos ($500, $300, $200 = $1 000 gravable). El cliente devuelve solo el producto de $300. Emites NC parcial:

curl
curl -X POST https://ocote.io/api/connect/credit-memo \
-H "Authorization: Bearer odt_xxx" \
-H "Content-Type: application/json" \
-d '{
"document_id": "CCF-ENLACES-TEST-001",
"external_ref": "NC-ENLACES-TEST-001",
"full_adjustment": false,
"lines": [
{
"description": "Silla ergonómica de oficina",
"quantity": 1,
"unit_price": 339.00
}
]
}'
Node.js (axios)
const { data } = await axios.post(
'https://ocote.io/api/connect/credit-memo',
{
document_id: 'CCF-ENLACES-TEST-001',
external_ref: 'NC-ENLACES-TEST-001',
full_adjustment: false,
lines: [
{ description: 'Silla ergonómica de oficina',
quantity: 1, unit_price: 339.00 },
],
},
{ headers: { Authorization: `Bearer ${process.env.OCOTE_API_KEY}` } }
);
Python (requests)
r = requests.post(
"https://ocote.io/api/connect/credit-memo",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"document_id": "CCF-ENLACES-TEST-001",
"external_ref": "NC-ENLACES-TEST-001",
"full_adjustment": False,
"lines": [
{
"description": "Silla ergonómica de oficina",
"quantity": 1,
"unit_price": 339.00,
},
],
},
)

Respuesta exitosa

{
"success": true,
"dte_success": true,
"contingency": false,
"rejected": false,
"posted": true,
"is_duplicate": false,

"document_id": "63e82935-9d98-43db-b2b8-bc669364885c",
"external_ref": "NC-ENLACES-TEST-001",
"control_number": "DTE-05-M001P002-000000000000001",
"generation_code": "63E82935-9D98-43DB-B2B8-BC669364885C",
"reception_stamp": "20260421145823...",

"ccf_control_number": "DTE-03-M001P002-000000000000008",
"ccf_adjusted_amount": 339.00,
"ccf_fully_adjusted": false,

"observaciones": [],
"dte_state": "",
"dte_message": ""
}

Observa:

  • ccf_control_number apunta al CCF ajustado — útil para tu conciliación.
  • ccf_adjusted_amount: 339.00 es el monto que esta NC descuenta del CCF.
  • ccf_fully_adjusted: false indica que el CCF aún tiene monto vigente — podrías emitir más NC si siguen llegando devoluciones, siempre dentro de los 90 días hábiles desde la emisión del CCF.

Ajuste total

Para anular un CCF completo vía NC (dentro de ventana):

curl
curl -X POST https://ocote.io/api/connect/credit-memo \
-H "Authorization: Bearer odt_xxx" \
-H "Content-Type: application/json" \
-d '{
"document_id": "CCF-ENLACES-TEST-002",
"full_adjustment": true,
"external_ref": "NC-ANULA-CCF-002"
}'

Este modo es equivalente a lo que hace POST /invalidate/{id} internamente cuando el CCF está fuera de ventana. La diferencia es que aquí tú tomas la decisión explícita.

Idempotencia y retry

Aplican las mismas reglas de Retry e idempotencia:

  • Mismo external_ref devuelto con éxito → is_duplicate: true, la NC original.
  • Mismo external_ref que falló previamente → reutiliza registro con el correlativo original, actualizando datos del payload nuevo.
  • El document_id del CCF no se puede cambiar en retry. El API ignora document_id del payload nuevo y conserva el CCF vinculado originalmente. Si quieres emitir NC sobre otro CCF, usa otro external_ref.

Descargar archivos

El endpoint POST /credit-memo no retorna invoice_url ni json_url en el response — solo los datos fiscales. Para obtener los URLs de descarga de una NC emitida, consulta el endpoint de estado:

curl
curl -H "Authorization: Bearer odt_xxx" \
https://ocote.io/api/connect/credit-memo/status/NC-ENLACES-TEST-001

La respuesta incluye invoice_url (PDF carta) y json_url (DTE firmado). Las NC no generan ticket térmico; solo los dos archivos mencionados. Ver Descargar archivos para detalle de auth dual y tabla completa por tipo de documento.

Ver también