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.
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.
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..."
}
| Campo | Tipo | Descripción |
|---|---|---|
preview | boolean | Siempre true. Este documento no es una factura. |
appliedDollarExchangeRate | number | null | Lempiras por USD aplicados. null si ninguna línea estaba en dólares. |
pdfBase64 | string | El 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.
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.
| HTTP | code | Causa |
|---|---|---|
| 400 | VALIDATION_FAILED | Body inválido o con campos desconocidos. |
| 400 | PRODUCT_NOT_FOUND | Un externalProductId no está mapeado. |
| 400 | EXTERNAL_INVOICE_NO_ITEMS | items vacío. |
| 400 | EXTERNAL_INVOICE_CLIENT_NOT_FOUND | El clientId no existe en tu empresa. |
| 400 | EXTERNAL_INVOICE_EXONERATION_REQUIRES_RTN | El cliente exonerado no tiene RTN. |
| 401 | MISSING_API_KEY / INVALID_API_KEY | Credencial. |
| 403 | INTEGRATION_NOT_ENABLED | Integración no habilitada. |
| 409 | INTEGRATION_MISSING_*, PRICE_NOT_FOUND | Configuración o catálogo incompletos. |
| 422 | EXTERNAL_INVOICE_CREDIT_NOT_SUPPORTED | isCredit: 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.