Acumatica gives you two ways to find out something changed: have it tell you (business events pushing to a webhook) or ask it repeatedly (polling the contract-based REST API on a schedule). Most integrations default to whichever pattern the developer built last, when the right choice actually depends on latency needs, endpoint availability, and how much you trust delivery guarantees.
How business event webhooks work
A business event in Acumatica watches for a condition — a document reaching a status, a field changing value — and fires a defined action when it's met. One of those actions can be an HTTP callout: Acumatica posts a payload to an external URL the moment the condition is satisfied. This gets you near-real-time notification without your integration ever asking Acumatica "did anything change." The AR Invoice released, the webhook fires seconds later, downstream systems react immediately.
The catch is that Acumatica's webhook delivery is fire-and-forget in the common configuration — there's no built-in dead-letter queue or guaranteed redelivery if your endpoint is down or returns an error. If your receiving service has an outage during the exact window a webhook fires, that event can simply be lost unless you've built retry logic on the Acumatica side (via a custom notification handler) or accept the gap.
How REST polling works
Polling flips the responsibility: a scheduled job calls the contract-based REST API on an interval, filtering for records modified since the last successful run (typically using a LastModifiedDateTime filter), and processes whatever comes back. Nothing gets silently lost — if a poll fails, the next one picks up the same unprocessed window, as long as you're tracking the watermark correctly.
async function pollInvoices(lastRunIso) {
const filter = `LastModifiedDateTime gt datetimeoffset'${lastRunIso}'`;
const res = await fetch(
`${BASE_URL}/entity/Default/23.200.001/Invoice?$filter=${encodeURIComponent(filter)}`,
{ headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' } }
);
if (!res.ok) throw new Error(`Poll failed: ${res.status}`);
const invoices = await res.json();
for (const inv of invoices) {
await processInvoice(inv);
}
return new Date().toISOString(); // new watermark, persist this
}
The trade-off is latency and cost: poll every five minutes and your worst-case delay is five minutes, poll every 30 seconds and you're hammering the API (and likely the license/session limits) for records that mostly haven't changed. Polling is inherently wasteful when nothing's happening, which is most of the time for a low-volume tenant.
Trade-offs at a glance
| Webhooks (business events) | REST polling | |
|---|---|---|
| Latency | Seconds | Bounded by poll interval |
| Delivery guarantee | Fire-and-forget by default | Guaranteed if watermark tracked correctly |
| Infra requirement | Public HTTPS endpoint | None — outbound calls only |
| Load on Acumatica | Minimal, event-driven | Recurring API/session cost |
| Reconciliation | Needs a separate safety net | Naturally self-healing |
When polling is the safer choice
Webhooks assume the receiving side has a stable, publicly reachable HTTPS endpoint — not always true for an on-prem integration behind a corporate firewall, or during early development when you don't want to expose anything to the internet yet. Polling also wins when you need a full reconciliation pass rather than a stream of deltas: end-of-day jobs that need to confirm every invoice is accounted for are naturally a polling problem, since "ask for everything modified since midnight" is a more complete guarantee than trusting that every webhook fired and was received.
If Acumatica itself is down or mid-upgrade when a business event would have fired, that event doesn't queue and retry once the instance comes back — it just doesn't happen. Any integration relying solely on webhooks needs a periodic reconciliation poll to catch what was missed during an outage window.
The hybrid pattern most integrations end up with
In practice, the reliable answer is both: use a webhook for near-real-time reaction to the events that matter, and run a much less frequent polling job — hourly or nightly — purely as a reconciliation safety net that catches anything the webhook missed. The webhook handles the "user expects to see this immediately" cases; the poll handles "make sure nothing fell through the cracks." Keep the reconciliation poll idempotent so reprocessing an already-handled record is harmless, and you get low latency without betting the integration's correctness on webhook delivery alone.
Wrapping up
Webhooks give you speed, polling gives you certainty — pick webhooks for responsiveness and pair them with a periodic poll for reconciliation rather than treating either pattern as sufficient on its own. That combination is what actually survives an Acumatica outage or a flaky endpoint without silently dropping data.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.