The Embedded Finance Index is live: 6,292 companies and 1,383 providers, mapped across the stack. Explore the Index →

How to Integrate with the Acumatica API

A developer guide to the Acumatica API: connected-app OAuth, per-customer instances, endpoint versions, paging, PUT upserts, push notifications and limits.

Saurabh RaiSaurabh Rai

Saurabh Rai · Developer Relations Engineer, Apideck

12 min readView as .md
How to Integrate with the Acumatica API

Acumatica shipped its 2026 R2 release on 1 October 2026, and with it a new default REST endpoint, version 26.200.001, that renames four fields, changes the value type of 237 others and changes the query syntax. Older endpoints keep working for now, but every Acumatica API integration eventually has to move, and the move touches most of the code that reads data. Plan your design around that from day one.

Acumatica is a cloud ERP for small and mid-sized companies, founded in 2008 and based in Bellevue, Washington. Its about page counts more than 10,000 customers and says it sells exclusively through partners. Vista Equity Partners agreed to acquire the company from EQT in May 2025. In Australia and New Zealand the same product is sold by MYOB, which renamed MYOB Advanced to MYOB Acumatica in July 2024. MYOB Acumatica runs the same core REST API, but MYOB warns developers not to assume that endpoint shape or release timing match standard Acumatica, so test against a MYOB instance too. Everything below applies to both, with MYOB differences called out where they matter.

Every customer is its own instance

There is no central Acumatica API host. Each customer runs an instance at its own URL, and every request goes to that URL. Inside an instance sit one or more tenants (separate companies with their own data), and inside a tenant sit branches. The REST API docs give the base URL as:

https://<instance-url>/entity/<endpoint-name>/<endpoint-version>/

For most integrations the endpoint name is Default, the system endpoint Acumatica maintains. The version varies per customer. The 2026 R2 help documents Default endpoints 26.200.001, 25.200.001, 24.200.001, 23.200.001, 22.200.001 and 20.200.001, and a customer's instance only offers the versions its release supports. A GET https://<instance-url>/entity call returns the build version and the list of endpoints available on that instance, which makes it a good first call when you connect a new customer.

Your onboarding flow therefore has to collect the instance URL and settle the endpoint version for each customer. Treat both as per-connection settings, not constants in your code.

Authentication: OAuth 2.0 through a connected application

Acumatica supports OAuth 2.0 and OpenID Connect with the authorization code, implicit, resource owner password and hybrid flows, per the authorization flows page. For a SaaS product, use the authorization code flow: your app never sees the user's Acumatica password, and, unlike the implicit flow, it can return a refresh token.

The older option is a cookie session: POST /entity/auth/login with a username, password, tenant and branch. The sign-in page states that direct sign-in with a username and password "is going to be discontinued in a future version" and recommends OAuth 2.0 or OIDC instead. Do not build anything new on it.

Registering the connected application

OAuth clients are registered inside the customer's instance, on the Connected Applications form (SM303010). There is no developer portal where you register once for all customers. The person registering has to be signed in to the tenant the app will access, and Acumatica generates the client ID in the format <GUID>@<tenant>, which binds the client to that tenant. The secret is shown once, so it has to be copied at creation time. Redirect URIs go on their own tab, must be absolute, and must match the URI in your authorization request exactly.

The same form controls refresh tokens. By default the whole refresh-token chain expires 30 days after the user first authorizes, after which they have to sign in again. The form also offers sliding expiration (including an infinite absolute lifetime) and a mode that disables refresh tokens entirely. For a background sync, ask the customer's admin to set sliding expiration when they create the app, or plan for a monthly re-authorization.

Five steps to connect one Acumatica customer: the customer registers a connected application and picks a refresh-token policy in their instance, then your app discovers the instance, runs the OAuth authorization code flow and calls the contract-based REST API

In practice this means your onboarding includes instructions for the customer's Acumatica admin, or their Acumatica partner, to create the connected application and hand you the client ID and secret.

The authorization code flow

Send the user to the authorize endpoint on their instance. This is the example from the OAuth docs, with a production redirect URI:

https://<instance-url>/identity/connect/authorize
  ?response_type=code
  &client_id=58FCCFBD-0CF3-C047-B720-A631C976A8DD@U100
  &redirect_uri=https%3A%2F%2Fyourapp.com%2Fcallback
  &scope=api%20offline_access

The api scope grants access to the REST API, the SOAP API and OData. offline_access adds the refresh token. A third scope, api:concurrent_access, lets one grant open several sessions, and Acumatica advises requesting it only if you need it, because each of those sessions then has to be signed out explicitly. PKCE is supported with code_challenge_method=S256.

Exchange the code at the token endpoint with a form-encoded body:

curl -X POST https://<instance-url>/identity/connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code&code=AUTH_CODE&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&redirect_uri=https%3A%2F%2Fyourapp.com%2Fcallback"

Access tokens last 3,600 seconds. When you refresh, Acumatica may return a new refresh token, and the refresh docs say to discard the old one and store the new one. If you need a refresher on storing and refreshing tokens per customer, our post on API integration best practices covers the patterns.

Every data call then carries Authorization: Bearer <access-token>. To act within a specific branch, add the PX-CbApiBranch header; Acumatica's docs say to pass the branch name, while a MYOB support article shows a branch ID, so test which one your customer's instance accepts. MYOB's article also shows why the header matters: without it, the session's default branch drives validation, and you get errors such as a vendor being "restricted" in a branch you never meant to post to.

Reading data from the Acumatica API

List requests are GET <base-url>/<Entity>, and the list docs support $filter, $select, $expand, $top and $skip. Nothing related is expanded by default, so ask for detail lines or linked contacts explicitly.

Pagination is offset-based with $top and $skip, and there is no parameter that returns a total count. Leave out $top and Acumatica returns every matching record, or an error if the instance has a SQL Server resource limit configured, so set $top on every list call. Our guide to API pagination compares offset and cursor paging, and why cursors hold up better when data changes between pages.

For incremental sync, filter on the last-modified timestamp. On endpoint 26.200.001, sales orders expose LastModifiedDateTime:

curl -G "https://<instance-url>/entity/Default/26.200.001/SalesOrder" \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  --data-urlencode "\$filter=LastModifiedDateTime gt datetimeoffset'2026-10-01T00:00:00+00:00'" \
  --data-urlencode "\$top=100" \
  --data-urlencode "\$skip=0"

On older endpoints the same field on SalesOrder is called LastModified, one of the renames that 26.200.001 introduced. Check the field name for each entity in the endpoint's OpenAPI document, which every instance serves at <base-url>/swagger.json?company=<tenant> per the OpenAPI docs. Generate your client from the customer's own instance, since a customized instance can differ from the stock one.

For reporting-style bulk reads, Acumatica also offers OData interfaces over generic inquiries and data access classes, at /t/<tenant>/api/odata/gi and /t/<tenant>/api/odata/dac. For anything you write back, stay on the contract-based REST API.

Writing data

Acumatica uses PUT to create and update. The create docs describe PUT as an upsert: it finds the record by its key fields or ID and updates it, or creates it if none exists. Add If-None-Match: * to make it create-only (you get a 412 if the record exists), or If-Match: * to make it update-only. For updates that should touch exactly the fields you send, use PATCH.

Each field value is wrapped in an object with a value property, per the entity format docs:

{
  "CustomerID": { "value": "JOHNGOOD" },
  "CustomerName": { "value": "John Good" }
}

Detail lines are arrays inside the record. To remove a line during an update, send it with its id (or key fields) and "delete": true. For very large documents the docs suggest splitting the lines across several requests; their example sends a 10,000-line sales order in batches of 500.

Business operations such as releasing an invoice are actions, called with POST on the entity. This is the release example from the 2026 R2 help:

curl -X POST "https://<instance-url>/entity/Default/26.200.001/SalesInvoice/ReleaseSalesInvoice" \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"entity":{"Type":{"value":{"id":"INV"}},"ReferenceNbr":{"value":"INV000046"}}}'

Actions can run long. A 202 response means the operation is still in progress, and you poll the URL in the Location header until it returns 204. The action docs add that other requests in the same session fail until the action finishes, so run releases in a session your other sync jobs do not share.

Validation errors come back as a 422 with an error property on each failing field, for example 'Customer' cannot be found in the system. Surface those to the user instead of retrying.

Webhooks and change notifications

Acumatica can push changes out through push notifications, configured on the Push Notifications form (SM302000). A notification watches a generic inquiry or a built-in query and posts the inserted and deleted rows to a webhook URL whenever the result changes. The payload carries an Id you can use to drop duplicates and a TimeStamp for ordering. When your endpoint returns an error, Acumatica retries, up to five attempts.

Each notification is set up on that form inside the customer's instance, usually by their admin or partner. Plan to poll with the last-modified filter above, and add push notifications for customers willing to configure them.

Rate limits come from the customer's license

Acumatica does not publish one rate limit for the API. Limits are set by each customer's license, and the April 2026 Licensing Guide lists the maximums per product edition, from 50 requests per minute on Essentials to 300 on Enterprise.

Bar chart of Acumatica API limits by edition from the April 2026 Licensing Guide: Essentials 50 requests per minute with a queue of 5, Select 100 and 10, Prime 150 and 20, Enterprise 300 and 40

Customers with reserved SaaS resources can buy higher limits. The license limits page describes how they are enforced. Once half the per-minute budget is used, Acumatica starts delaying requests, and it queues requests above the concurrency limit without telling you. A request is only declined, with HTTP 429, when more than 20 requests are queued or one has waited more than 10 minutes. Track response times per customer: they climb well before you see a 429.

Sessions are the other limit. Each license allows a fixed number of API sessions, and an unclosed session keeps its slot until a 10-minute timeout. With the plain api scope, the session tied to an access token closes when the token expires after an hour. Acumatica still recommends signing out with POST /entity/auth/logout when you are done, and the troubleshooting page lists "wait for one hour" as one fix for the "API Login Limit" error. A sync that leaks sessions can lock other integrations, and your own next run, out of the customer's instance.

Your integration also shares these limits with every other app the customer has connected, so budget well below the edition's number.

MYOB Acumatica sells API access separately. MYOB's API licence page lists a free "Full User API" licence capped at 1,500 calls per day for one named API user, and a paid "Full Access API" licence with unlimited calls. Login and logout each count as a call.

Testing and certification

You can run Acumatica locally: builds.acumatica.com hosts the installers, and the help's examples use a new instance with the T100 demo dataset together with a Postman collection on GitHub. Acumatica's developer quick-start (updated August 2025) says a local instance is fully functional apart from a limit of two concurrent users, and that the Acumatica Developer Network offers hosted SaaS instances for ISVs at $5,160 a year. The trial license caps API sessions at two, so expect session errors early if your test suite does not sign out.

To list an integration on the Acumatica Marketplace, Acumatica certifies it in its labs through the Acumatica Developer Network. On the MYOB side, the MYOB Acumatica developer program gives developers a sandbox, and access to MYOB's technical support portal requires completing the Acumatica Integration Developer Certification course. To go live with a MYOB customer, that customer buys an API licence and assigns the login to you.

Upgrades are the long-term cost

Acumatica ships two releases a year and in most cases supports each for 18 months, per the Licensing Guide. SaaS customers on its Always Current program are upgraded within 120 days of each release they are scheduled for, every six months, or every twelve for customers above Essentials who choose it. Old Default endpoints keep working for a while, but the endpoint docs warn that "obsolete system endpoints may be removed in some version", and contract versions 2 and 3 lost support in 2023 R2.

Moving to 26.200.001 also means moving to contract version 5, which changes the query syntax: $expand and $select nest in parentheses, custom fields move from $custom into $select, and filters on drop-down fields use internal IDs instead of descriptions. The 26.200.001 change list gives 237 fields, most of them drop-downs and date-only fields, a new value type. Customer customizations add their own fields on top of that. Plan for an endpoint migration every year or so, and test against each customer's endpoint list before you assume a version.

If Acumatica is the only ERP your customers use, building directly is a reasonable project. Once a second ERP lands on your roadmap, you take on a second auth model and a second upgrade cycle; our guide to building ERP extensions compares how the major ERPs differ. Apideck's Accounting API connects to Acumatica and MYOB Acumatica today through one normalized REST API, with the connected-application OAuth flow handled in Apideck Vault, so you can start with Acumatica and add the next ERP without another integration project.

Ready to get started?

Scale your integration strategy and deliver the integrations your customers need in record time.

Ready to get started?
Talk to an expert

Frequently asked questions

Trusted by fast-moving product & engineering teams

Bonsai by Zoom
JobNimbus
Blue Zinc
Exact
Drata