Skip to Content
v1.5Official documentation for the LX CloudPos API · stable in production

Polling vs webhook

Hacienda (Costa Rica’s tax authority) takes seconds or minutes to resolve a document. There are two ways to learn the result: querying repeatedly (polling) or receiving a notification (webhook). The first is simple, but expensive and slow; the second is the recommended option whenever you can expose a public endpoint.

What gets retried and what doesn’t

It’s worth distinguishing three elements that tend to get conflated into one:

WhatRetry
Sending the document to Hacienda5 attempts, backoff from 10 s to 5 min
Querying Hacienda for the final statusevery 10 min, no time limit, until it responds
Delivering the webhook to the integrator3 in-process attempts (0 s / 2 s / 8 s) + 2 by cron every 10 min

The first two correspond to LX CloudPos talking to Hacienda; the third is delivery to the integrator. Even so, GET /api/v1/facturas/{clave} is always the source of truth for the status: it’s fed by the second row’s sweep, regardless of whether the webhook was delivered.

Query the document’s detail in a loop until its status changes. This is useful for local testing or when you can’t expose a public endpoint.

async function esperarHacienda(clave, maxIntentos = 30) { for (let i = 0; i < maxIntentos; i++) { const { data } = await axios.get(`/api/v1/facturas/${clave}`); if (data.estadoHacienda === 'aceptado') return data; if (data.estadoHacienda === 'rechazado') throw new Error('Rechazado'); await sleep(30000); // 30s } throw new Error('Timeout esperando Hacienda'); }

The document is issued and requires no active follow-up. LX CloudPos notifies you when Hacienda responds, and the integrator only reads the result from its own database.

// 1. Issuer: issue and forget await emitirFactura(data); // 2. Webhook receiver: record the result app.post('/webhooks/lxs', verificarHmac, async (req, res) => { const evento = parsearEvento(req.body); await db.facturas.update({ where: { clave: evento.clave }, data: { estadoFinal: evento.ind_estado } }); res.status(200).end(); }); // 3. Frontend: query your own DB's status, without touching the API