Saltar al contenido principal

POST /v1/invoices/preview

Calcula y renderiza la factura con tu configuración real —tus productos, tu lista de precios, tus tasas de ISV, tu membrete— usando el mismo motor y la misma plantilla que una factura real, y luego descarta el documento.

Este es el endpoint para probar tu integración. No consume CAI, no avanza el correlativo y no escribe nada: todo lo que hace son lecturas. Úsalo para verificar precios, impuestos y el formato impreso antes de emitir tu primera factura de verdad.

consejo

No lleva Idempotency-Key

Es el mismo body que POST /v1/invoices, pero sin ese header: no hay nada que reintentar de forma idempotente porque no se emite nada. Reintenta con la libertad que quieras.

peligro

El PDF de una previsualización no es una factura

Sale marcado SIN VALIDEZ FISCAL y con el CAI enmascarado. No lo entregues a un cliente final: no sustituye un comprobante.

Solicitud

curl -s -X POST https://integration.contadito.com/v1/invoices/preview \
-H "Authorization: Bearer $CONTADITO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"clientId": 1042,
"items": [
{ "externalProductId": "SKU-WEB-HOSTING-01", "quantity": 2 }
]
}'

El body es idéntico al de POST /v1/invoices, con las mismas reglas: items obligatorio, clientId opcional (salvo en ventas exoneradas), isCredit: true rechazado con 422.

También admite items[].price, y es el lugar donde conviene comprobarlo: un precio negociado sobre un producto en dólares o parcialmente gravado no siempre da el total que uno espera.

Respuesta 200

{
"preview": true,
"invoiceDate": "2026-08-10T15:04:05.000Z",
"clientId": 1042,
"importe": 2000,
"discountTotal": 0,
"exemptedAmount": 0,
"exoneratedAmount": 0,
"totalTaxes": 300,
"total": 2300,
"totalInLetters": "DOS MIL TRESCIENTOS LEMPIRAS EXACTOS",
"appliedDollarExchangeRate": null,
"taxBreakdown": [{ "rate": 15, "taxAmount": 300, "taxedAmount": 2000 }],
"lines": [
{
"externalProductId": "SKU-WEB-HOSTING-01",
"quantity": 2,
"unitPrice": 1000,
"importe": 2000,
"discountAmount": 0,
"subTotal": 2000,
"exemptAmount": 0
}
],
"pdfBase64": "JVBERi0xLjQK..."
}
CampoTipoDescripción
previewbooleanSiempre true. Este documento no es una factura.
appliedDollarExchangeRatenumber | nullLempiras por USD aplicados. null si ninguna línea estaba en dólares.
pdfBase64stringEl PDF A4 en base64, marcado SIN VALIDEZ FISCAL.

Los totales, taxBreakdown y lines son los mismos campos que en POST /v1/invoices y se calculan igual.

No hay id, invoiceNumber ni cai: no se emitió nada, así que no hay nada que referenciar después. Tampoco hay replayed.

nota

A diferencia de una lectura, aquí exemptAmount de cada línea sí trae el monto exento calculado.

Para ver el PDF:

curl -s -X POST https://integration.contadito.com/v1/invoices/preview \
-H "Authorization: Bearer $CONTADITO_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "items": [{ "externalProductId": "SKU-WEB-HOSTING-01", "quantity": 2 }] }' \
| python3 -c 'import json,sys,base64; sys.stdout.buffer.write(base64.b64decode(json.load(sys.stdin)["pdfBase64"]))' \
> preview.pdf

Errores

Los mismos que POST /v1/invoices, menos los de idempotencia.

HTTPcodeCausa
400VALIDATION_FAILEDBody inválido o con campos desconocidos.
400PRODUCT_NOT_FOUNDUn externalProductId no está mapeado.
400EXTERNAL_INVOICE_NO_ITEMSitems vacío.
400EXTERNAL_INVOICE_CLIENT_NOT_FOUNDEl clientId no existe en tu empresa.
400EXTERNAL_INVOICE_EXONERATION_REQUIRES_RTNEl cliente exonerado no tiene RTN.
401MISSING_API_KEY / INVALID_API_KEYCredencial.
403INTEGRATION_NOT_ENABLEDIntegración no habilitada.
409INTEGRATION_MISSING_*, PRICE_NOT_FOUNDConfiguración o catálogo incompletos.
422EXTERNAL_INVOICE_CREDIT_NOT_SUPPORTEDisCredit: true.

A diferencia de POST /v1/invoices, la previsualización no exige un terminal de pago configurado: puedes previsualizar con INTEGRATION_MISSING_PAYMENT_TERMINAL pendiente.

Ver el catálogo completo de errores.