Acumatica · Api

Acumatica OAuth 2.0 Setup — Step by Step

How to register an OAuth client in Acumatica, configure scopes, request tokens, and use them against the contract-based REST API. Includes both authorization-code and client-credentials flows.

John Kihiu12 min read

Every Acumatica integration I take over that still logs in with /entity/auth/login and a session cookie eventually hits the same walls: sessions pinned to one node behind a load balancer, mysterious 401s when a session expires mid-batch, and API users locked out because the password rotated. OAuth 2.0 fixes all of it, and setting it up takes about fifteen minutes once you know the screens. Here's the exact sequence I use.

Step 1: Register a connected application

Go to Integration > Connected Applications (SM303010). Create a new record:

Save the record — Acumatica generates the Client ID, which is a GUID suffixed with the tenant name, like 4B1E...@CompanyTenant. That suffix matters: it routes the token request to the right tenant, so don't trim it.

Then, on the Secrets tab, click Add Shared Secret. Give it a description and an expiration date. The secret value is shown once. Copy it into your secrets manager immediately; if you lose it you'll be adding a new one, not recovering it.

Step 2: Choose the right flow

For 90% of ERP integrations — a Laravel backend, an Azure Function, a middleware box — the consumer is a machine, and Resource Owner Password Credentials (ROPC) with a dedicated API user is the pragmatic choice. Yes, ROPC is deprecated in the broader OAuth world; in Acumatica's context it's the supported server-to-server pattern and it's still a huge upgrade over cookie sessions. Authorization Code (with PKCE if the client is public) is correct when a real user should authenticate — say, a portal where each user's Acumatica permissions must apply.

Step 3: Create a dedicated API user

Never run integrations as a person. Create a user like svc-warehouse, assign it the narrowest roles that cover the entities it touches, and — critically — set its date format and locale deliberately, because responses are formatted per user settings. Also confirm the user's license type: on newer licenses, API users are a separate, unlimited category that doesn't burn an interactive seat, but they must be flagged accordingly on the Users screen.

Step 4: Request a token

HTTP
POST /identity/connect/token HTTP/1.1
Host: yourinstance.acumatica.com
Content-Type: application/x-www-form-urlencoded

grant_type=password
&client_id=4B1E7A22-...@CompanyTenant
&client_secret=YOUR_SECRET
&username=svc-warehouse
&password=THE_API_USER_PASSWORD
&scope=api offline_access

The response contains access_token, expires_in (3600 seconds by default), and — because we asked for offline_access — a refresh_token. The scopes worth knowing:

Step 5: Use the token, refresh before expiry

Send Authorization: Bearer eyJhbGciOi... on every request. For refresh, post grant_type=refresh_token with the refresh token to the same endpoint. My client code refreshes proactively at 80% of expires_in rather than reacting to 401s — reactive refresh works, but it turns every expiry into a failed request in your logs and a retry you have to reason about.

Gotcha: locked-out API users fail with a token error, not a clear message

If the API user's password expires or the account locks after failed attempts, the token endpoint returns a generic invalid_grant. Set the API user's password to not expire (policy permitting) and alert on invalid_grant in your integration logs — it almost always means credentials, not code.

Step 6: Verify end to end

Prove the whole chain with one call:

HTTP
GET /entity/Default/24.200.001/StockItem?$top=1 HTTP/1.1
Host: yourinstance.acumatica.com
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...

A 200 with one item means the connected app, secret, user, roles, and endpoint version are all aligned. A 401 here with a valid token usually means the user lacks access rights to the entity's screen; a 403/500 mentioning the endpoint usually means a version mismatch — list available endpoints at /entity to check what the instance actually exposes.

Operational notes from production

Wrapping up

The sequence is short: connected application, shared secret, dedicated API user with minimal roles, token request with api offline_access (plus api:concurrent_access if you parallelize), proactive refresh, and a smoke-test GET. Do it once properly and authentication becomes the one part of your Acumatica integration you never think about again — which is exactly what auth should be.

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.