API · Api

Acumatica REST API — Error Handling Patterns

A practical taxonomy of Acumatica REST API errors — validation, concurrency, session, licence — and the handling code patterns that keep your integration quiet in production.

John Kihiu12 min read

Acumatica's REST API returns errors as JSON, but the shape and the right response to them varies a lot more than "check the status code." Because every request runs through the same business logic as the UI, a good chunk of "errors" are really validation messages the screen would also have shown a user — and those need to be handled differently from a genuine infrastructure failure.

The shape of an error response

A failed request typically comes back with a JSON body carrying a message field summarizing the problem, and often an exceptionType naming the underlying .NET exception — commonly something in the PX.Data.PXException family for business-logic failures. Field-level validation errors (a required field missing, a value outside an allowed range) tend to surface inside that message text rather than as a structured per-field error list, so parsing them reliably often means matching on message substrings rather than a clean error code.

JSON · TYPICAL ERROR BODY
{
  "message": "The record cannot be saved.",
  "exceptionMessage": "'Customer' cannot be empty.",
  "exceptionType": "PX.Data.PXException"
}

Validation errors vs. infrastructure failures

A 400 carrying a PXException about a missing required field is not transient — retrying the identical payload will fail identically forever. A 500, a timeout, or a connection reset might be transient — a deployment restart, a saturated API core, a brief database hiccup. Treating both the same way (blind retry-on-any-failure, or blind fail-fast-on-any-failure) is the most common error-handling bug in Acumatica integrations: it either hammers a request that can never succeed, or gives up on one that would have worked on the next attempt.

Mapping business logic errors back to users

Because validation messages come from the same business logic as the screen, they're usually written for a person looking at that screen, not for a downstream system. "'Customer' cannot be empty" is clear enough to relay directly in a lot of integrations; a more obscure message from deep in an event handler chain often needs translating into something the integration's own users can act on, rather than surfacing the raw Acumatica exception text verbatim.

Log the exceptionMessage, not just the status code

A logging setup that only records "PUT to SalesOrder failed: 400" throws away the one piece of information that tells you why. Always persist the message/exceptionMessage body alongside the status code — it's usually the fastest path to root-causing a failed integration run without reproducing it by hand.

Partial failure in multi-step operations

An entity payload with nested detail lines (a Sales Order with its lines, for instance) is saved as one transaction — a validation failure on one line fails the whole PUT, it doesn't save the header and skip the bad line. Design integration logic around that: if you need partial success semantics (save what's valid, report what isn't), you generally have to split the work into separate calls yourself rather than relying on the API to do it for you.

A practical error-handling shape

In practice: check status code first — 2xx success, 4xx don't retry (log and surface to a human or a dead-letter queue), 5xx/timeout retry with backoff up to a small cap. Parse the message body on every failure regardless of status code, because that's where the actionable detail lives. And keep a dead-letter path for anything that exhausts retries or fails validation, so a bad record doesn't silently vanish from the integration's throughput.

Wrapping up

Acumatica's REST errors are business-logic messages wearing an HTTP status code — treat the status as a rough retry/don't-retry signal and the message body as the actual diagnostic. Log both, split multi-line payloads if you need partial success, and never retry a 400 hoping it becomes valid on the third attempt.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.