Crea y emite una Nota de Credito o Debito contra una factura original validada por el SIAT. La nota permite ajustar montos por devoluciones parciales o totales.
La factura original debe estar en estado VALIDATED. No se puede emitir una nota contra facturas rechazadas, anuladas o pendientes.
Path Parameters
| Parametro | Tipo | Req | Descripcion |
|---|
id | UUID | Si | UUID de la factura original contra la que se emite la nota |
| Parametro | Tipo | Req | Descripcion |
|---|
X-API-Key | string | Si | Tu API Key |
Content-Type | string | Si | application/json |
Request Body
| Campo | Tipo | Req | Descripcion |
|---|
pointOfSaleId | UUID | Si | UUID del punto de venta registrado en SIAT |
notaType | string | Si | Tipo de nota: CREDITO o DEBITO |
documentSectorType | integer | No | Sector de la nota: 24 (estandar, default), 47 (Nota Descuento) o 48 (Nota ICE). Ver Notas Descuento e ICE |
paymentMethodCode | integer | Si | Codigo de metodo de pago (1-308). 1 = Efectivo |
cardNumber | string | No | Numero de tarjeta. Se ofusca automaticamente antes de guardar y emitir (ver nota de seguridad) |
observations | string | No | Observaciones (max 500 caracteres) |
isTicket | boolean | No | true para generar ticket 80mm ademas de A4 |
returnedDetails | array | Si | Items devueltos/ajustados (minimo 1) |
originalDetails | array | No | Solo sector 48 (ICE): overlay de datos ICE por linea original. En sectores 24/47 se ignora. Ver Notas Descuento e ICE |
returnedDetails[]
| Campo | Tipo | Req | Descripcion |
|---|
activityEconomic | string | Si | Codigo de actividad economica CAEB |
codeProductSin | string | Si | Codigo de producto/servicio del catalogo SIN |
codeProduct | string | No | Codigo interno del producto |
description | string | Si | Descripcion del producto o servicio devuelto (max 500) |
quantity | number | Si | Cantidad devuelta (mayor a 0) |
unitMeasure | integer | Si | Unidad de medida SIN. 58 = Servicio, 1 = Unidad |
priceUnit | number | Si | Precio unitario en bolivianos (mayor a 0) |
amountDiscount | number | No | Descuento aplicado al item (default 0) |
serialNumber | string | No | Numero de serie (si aplica) |
imeiNumber | string | No | Numero IMEI (si aplica) |
curl -X POST "https://sandbox.cucu.bo/api/v1/invoices/a1b2c3d4-e5f6-7890-abcd-ef1234567890/credit-note" \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-d '{
"pointOfSaleId": "660e8400-e29b-41d4-a716-446655440004",
"notaType": "CREDITO",
"paymentMethodCode": 1,
"returnedDetails": [
{
"activityEconomic": "620100",
"codeProductSin": "83141",
"description": "Devolucion parcial - Servicio de software",
"quantity": 1,
"unitMeasure": 58,
"priceUnit": 200.00
}
]
}'
const response = await fetch(
'https://sandbox.cucu.bo/api/v1/invoices/a1b2c3d4-e5f6-7890-abcd-ef1234567890/credit-note',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': 'YOUR_API_KEY'
},
body: JSON.stringify({
pointOfSaleId: '660e8400-e29b-41d4-a716-446655440004',
notaType: 'CREDITO',
paymentMethodCode: 1,
returnedDetails: [{
activityEconomic: '620100',
codeProductSin: '83141',
description: 'Devolucion parcial - Servicio de software',
quantity: 1,
unitMeasure: 58,
priceUnit: 200.00
}]
})
}
);
const data = await response.json();
import requests
response = requests.post(
'https://sandbox.cucu.bo/api/v1/invoices/a1b2c3d4-e5f6-7890-abcd-ef1234567890/credit-note',
headers={
'Content-Type': 'application/json',
'X-API-Key': 'YOUR_API_KEY'
},
json={
'pointOfSaleId': '660e8400-e29b-41d4-a716-446655440004',
'notaType': 'CREDITO',
'paymentMethodCode': 1,
'returnedDetails': [{
'activityEconomic': '620100',
'codeProductSin': '83141',
'description': 'Devolucion parcial - Servicio de software',
'quantity': 1,
'unitMeasure': 58,
'priceUnit': 200.00
}]
}
)
print(response.json())
{
"success": true,
"message": "Nota creada exitosamente",
"data": {
"id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"invoiceNumber": 10,
"cuf": "3983G8305613443F748GCBGCD4765FB93313BE59F1A7AF25FCFC9BG85",
"state": "VALIDATED",
"clientBusinessName": "EMPRESA DEMO S.R.L.",
"amountTotal": 200.00,
"emissionDate": "2026-02-22T10:30:00",
"pdfUrl": "https://sandbox.cucu.bo/api/v1/public/invoice/3983G...G85/pdf",
"xmlUrl": "https://sandbox.cucu.bo/api/v1/public/invoice/3983G...G85/xml"
},
"timestamp": "2026-02-22T10:30:00"
}
{
"success": false,
"error": {
"code": "BAD_REQUEST",
"details": "La factura original no tiene detalles suficientes para la devolucion solicitada"
},
"timestamp": "2026-02-22T10:30:00"
}
{
"success": false,
"error": {
"code": "CONFLICT",
"details": "La factura original no esta en estado VALIDATED"
},
"timestamp": "2026-02-22T10:30:00"
}
Notas Descuento e ICE (sectores 47 y 48)
Ademas de la nota estandar (24), el campo documentSectorType permite emitir dos variantes especializadas:
| Sector | Tipo | Cuando usarlo |
|---|
24 | Nota Credito-Debito estandar | Default. Devoluciones/ajustes normales |
47 | Nota Credito-Debito Descuento | La factura original tenia descuento adicional prorrateado por item |
48 | Nota Credito-Debito ICE | La factura original tenia productos con Impuesto al Consumo Especifico (ICE) |
No re-envies las lineas de la factura original. En los tres sectores, las lineas originales
(codigoDetalleTransaccion=1) se clonan automaticamente desde la base de datos — espejan
exacto la factura registrada en SIAT. Enviar tus propias lineas originales causaba rechazos
SIAT [1049] (detalle diferente) y [1030] (monto original erroneo). Ahora solo mandas los
items devueltos en returnedDetails.
Sector 47 — solo returnedDetails
Identico al 24 a nivel de request: mandas unicamente returnedDetails. El campo originalDetails, si viene, se ignora.
Sector 48 — returnedDetails + overlay ICE
La compra-venta original no almacena los montos ICE, asi que en el sector 48 esos numeros
si vienen del request, en originalDetails, como un overlay minimal matcheado por nroItem.
La base (actividad/producto/descripcion/cantidad/precio) se toma de la BD; en originalDetails
solo importan los campos ICE:
| Campo | Tipo | Descripcion |
|---|
nroItem | integer | lineNumber de la linea original a la que aplica el overlay (lo obtienes de GET /invoices/{id} → details[].lineNumber) |
marcaIce | integer | 1 = considera ICE, 2 = no considera ICE. Obligatorio |
montoIceEspecifico | number | Monto ICE especifico de la linea (opcional) |
montoIcePorcentual | number | Monto ICE porcentual de la linea (opcional) |
En sectores 47/48, cada returnedDetails[].nroItem tambien referencia el lineNumber
de la linea original que se devuelve (para el prorrateo del descuento). Consulta los numeros
de linea de la factura original con GET /api/v1/invoices/{id} → details[].lineNumber.
Ejemplo originalDetails (sector 48)
"originalDetails": [
{ "nroItem": 1, "marcaIce": 2, "montoIceEspecifico": 0, "montoIcePorcentual": 0 }
]
Modo estructural: si la factura original no tenia ICE, envia marcaIce: 2 con montos en 0.
La nota se emite con la estructura ICE requerida por el XSD del sector 48 pero sin monto ICE real.
Comportamiento
- El sistema obtiene automaticamente los datos de la factura original (cliente, CUF, montos)
- Los
returnedDetails se marcan con codigoDetalleTransaccion=2 (devolucion)
- Los items originales se clonan desde la base de datos con
codigoDetalleTransaccion=1 (nunca del request)
- Se calcula:
montoTotalOriginal, montoTotalDevuelto, montoDescuentoCreditoDebito, montoEfectivoCreditoDebito
- La nota se envia al SIAT via el WSDL de documento de ajuste (sector 24/47/48 segun
documentSectorType)
- Se genera PDF (A4 + ticket opcional), XML y se envia email al cliente
Si la factura original tiene items con montoGiftCard > 0, el paymentMethodCode debe incluir el codigo 27 (Gift Card). Error SIAT 1050 si se omite.
La nota genera su propio CUF unico. Puedes acceder a ella via /f/{cuf} o los endpoints publicos, igual que una factura regular.
Seguridad — ofuscacion de tarjeta. Si envias cardNumber, la API conserva solo los 4 primeros
y 4 ultimos digitos y reemplaza el resto por ceros antes de persistir y emitir el XML SIAT
(ej: 4111111111111111 → 4111000000001111). El numero completo (PAN) nunca se guarda en la base
de datos ni viaja al SIAT. Numeros de 8 digitos o menos se dejan tal cual.