Acumatica Screen-Based API: How It Works and When to Use It vs REST

Type: ERP Integration System: Acumatica ERP (2024 R2 / 24.200) Confidence: 0.88 Sources: 7 Verified: 2026-03-02 Freshness: 2026-03-02

TL;DR

System Profile

This card covers Acumatica ERP's screen-based SOAP web services API and compares it with the contract-based REST API. The screen-based API has been available since Acumatica's earliest versions and provides direct programmatic access to every form in the system. The contract-based REST API was introduced in Acumatica 5.3 (2016) as a more stable, decoupled alternative. Both APIs are available in all Acumatica editions across cloud, hosted, and on-premise deployments. This card does NOT cover OData-based data retrieval.

PropertyValue
VendorAcumatica
SystemAcumatica ERP 2024 R2 (24.200)
API SurfaceSOAP (Screen-Based) + REST (Contract-Based) + OData
Current API VersionScreen-Based: per-screen WSDL; REST: 24.200.001
Editions CoveredSmall Business, Standard, Enterprise
DeploymentCloud / Hosted / On-Premise
API DocsAcumatica Integration Development Guide
StatusScreen-Based: Maintenance; REST: GA (actively developed)

API Surfaces & Capabilities

Acumatica provides three distinct API surfaces, each with different strengths and trade-offs. The screen-based API offers the broadest functional coverage but the least stability; the contract-based REST API offers stability and ease of use but may not expose every screen action. [src1, src3]

API SurfaceProtocolBest ForStabilityCoverageReal-time?Bulk?
Screen-Based SOAPHTTPS/XML (SOAP)Automating any screen action, processing screens, legacyLow - breaks on UI changesComplete (every form)YesVia Export/Import
Contract-Based RESTHTTPS/JSON (REST)CRUD operations, new integrations, cross-platformHigh - decoupled from UIPartial (configured endpoints)YesLimited
Contract-Based SOAPHTTPS/XML (SOAP)Legacy contract-based integrationsHigh - decoupled from UISame as RESTYesLimited
OData (GI-Based)HTTPS/JSON (OData v4)BI tools, reporting, read-onlyHighGeneric Inquiries onlyYesRead-only
OData (DAC-Based)HTTPS/JSON (OData v4)Direct DAC access for reportingHighDAC-exposed entitiesYesRead-only

Rate Limits & Quotas

Per-Request Limits

Limit TypeValueApplies ToNotes
Max concurrent API user sessionsLicense-dependentAll API surfacesConfigured on SM604000; exceeding returns login error
Request body sizeNo published hard limitREST APIDenial Code 511 returned for oversized payloads
Export batch sizeConfigurable per callScreen-Based Export()Set via TopCount parameter
Composite batch size1,000 per $batchREST APIEach subrequest counts as a separate API call

Rolling / Daily Limits

Limit TypeValueWindowEdition Differences
API requests per minuteLicense-dependentPer minuteAt 50% of limit, requests are throttled; at 100%, rejected
Concurrent API usersLicense-dependentConcurrent sessionsSmall Business: fewer; Enterprise: more. Check SM604000
Total API callsNo published daily cap24hGoverned by per-minute rate limit and concurrent user limit

Authentication

Acumatica supports multiple authentication methods across its API surfaces. OAuth 2.0 is recommended for all new integrations. The screen-based API historically used cookie-based authentication via Login/Logout SOAP methods, but OAuth 2.0 tokens can also be used. [src3, src7]

FlowUse WhenToken LifetimeRefresh?Notes
OAuth 2.0 Authorization CodeInteractive applications, user-contextConfigurableYesRegister on SM303010 (Connected Applications)
OAuth 2.0 Resource Owner PasswordServer-to-server integrationsConfigurableYesSimpler setup but less secure
Cookie-based (Login/Logout SOAP)Legacy screen-based API integrationsSession-basedNoUses Login() method with username, password, company, branch
OAuth 2.0 Client CredentialsService-to-service, no user contextConfigurableYesAvailable in newer Acumatica versions

Authentication Gotchas

Constraints

Integration Pattern Decision Tree

START - Need to integrate with Acumatica ERP
|-- Is this a new integration or maintaining an existing one?
|   |-- NEW integration
|   |   |-- Do you need to automate a screen action not exposed via REST?
|   |   |   |-- YES --> Screen-Based SOAP API (only option)
|   |   |   |-- NO --> Contract-Based REST API (recommended)
|   |   |-- Do you need read-only data for BI/reporting?
|   |   |   |-- YES --> OData (GI-based or DAC-based)
|   |   |   |-- NO --> REST API
|   |   |-- What client environment?
|   |       |-- .NET --> REST API or Screen-Based with PX.Soap.dll
|   |       |-- Non-.NET (Python, JS, Java) --> REST API (no wrapper)
|   |-- EXISTING screen-based integration
|       |-- Is it working and stable?
|       |   |-- YES --> Keep it, plan migration to REST over time
|       |   |-- NO (breaking on upgrades) --> Migrate to REST now
|       |-- Can all operations be replicated with REST?
|           |-- YES --> Migrate to REST API
|           |-- NO --> Keep screen-based for those ops, REST for rest
|-- Data flow direction?
|   |-- Read/Export --> REST API GET or Screen-Based Export()
|   |-- Write/Import --> REST API PUT/POST or Screen-Based Import()
|   |-- React to changes --> Push Notifications or Webhooks
|-- Error handling?
    |-- Zero-loss required --> Idempotency + GetProcessStatus() polling
    |-- Best-effort --> REST API with retry on 429/500

Quick Reference

OperationScreen-Based APIContract-Based REST APINotes
Endpoint URL{site}/Soap/{FormID}.asmx{site}/entity/{EndpointName}/{Version}/{Entity}Screen-based uses form IDs (e.g., AR301000.asmx)
WSDL{site}/Soap/{FormID}.asmx?WSDLN/A (OpenAPI via SM207000)Screen-based generates WSDL per form
Create recordSubmit() with Content objectPUT /entity/Default/24.200.001/{Entity}REST uses JSON; screen-based uses SOAP XML
Read recordsExport() with filtersGET /entity/Default/24.200.001/{Entity}?$filter=...REST supports OData query syntax
Update recordSubmit() with modified ContentPUT /entity/Default/24.200.001/{Entity}Both use record key fields
Delete recordClear() then Submit()DELETE /entity/Default/24.200.001/{Entity}/{keys}Screen-based requires clearing then submitting
Execute actionSubmit() with action triggerPOST .../SalesOrder/ReleaseOrderScreen-based can trigger any button; REST only configured actions
Check async statusGetProcessStatus()GET .../{Entity}?$longRunning=trueScreen-based has dedicated polling method
LoginLogin(name, password, company, branch)OAuth 2.0 Bearer tokenScreen-based: session cookie; REST: Authorization header
LogoutLogout()N/A (token expiry)Screen-based MUST call Logout() to free session
Schema discoveryGetSchema() / SetSchema()/entity/Default/24.200.001Screen-based caches schema locally via PX.Soap.dll

Step-by-Step Integration Guide

1. Determine which API surface to use

Evaluate whether the integration requires screen-specific functionality. Only fall back to screen-based API when you need access to processing screens, custom actions, or form-specific logic not exposed through contract-based endpoints. [src1]

Decision checklist:
- [ ] Can the operation be done via REST API endpoint? --> Use REST
- [ ] Does it require a specific screen action? --> Check REST endpoint first
- [ ] Is the client .NET? --> Screen-based option available
- [ ] Is the client non-.NET? --> Must use REST API
- [ ] Is this a greenfield integration? --> Use REST API

Verify: Check REST endpoint configuration on SM207000 to see if your required entities and actions are exposed.

2. Set up authentication (REST API - recommended)

Register your application on SM303010 (Connected Applications) for OAuth 2.0. [src3, src7]

# Obtain access token (Resource Owner Password flow)
curl -X POST "https://your-instance.acumatica.com/identity/connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "username=admin" \
  -d "password=YOUR_PASSWORD" \
  -d "scope=api"

Verify: GET /entity/Default/24.200.001/ returns a list of available entities.

3. Set up authentication (Screen-Based API - legacy)

For screen-based SOAP integrations, use the Login() method via PX.Soap.dll wrapper. [src4]

// Create SOAP client for Sales Order screen (SO301000)
var soapClient = new SO301000Screen();
soapClient.Url = url + "/Soap/SO301000.asmx";
soapClient.CookieContainer = new System.Net.CookieContainer();
soapClient.Login(username, password, company, null, null);
// Always call soapClient.Logout() when done

Verify: A successful Login() call returns without error.

4. Perform CRUD via REST API

Use standard REST methods for creating, reading, updating, and deleting records. [src3, src7]

# Query stock items with filter
curl -X GET "https://your-instance.acumatica.com/entity/Default/24.200.001/StockItem?\$filter=InventoryID eq 'AALEGO500'" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Accept: application/json"

# Create a stock item (PUT for upsert)
curl -X PUT "https://your-instance.acumatica.com/entity/Default/24.200.001/StockItem" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"InventoryID":{"value":"NEWITEM001"},"Description":{"value":"New Test Item"},"ItemClass":{"value":"STOCKITEM"}}'

Verify: GET query with filter returns the created record.

5. Perform operations via Screen-Based API (when REST is insufficient)

Use for operations that require specific screen actions not exposed through REST endpoints. [src4]

var schema = PX.Soap.Helper.GetSchema<SO301000Content>(soapClient);
var commands = new SO301000Command[]
{
    schema.Actions.Insert,
    new SO301000Value { Value = "SO", LinkedCommand = schema.OrderSummary.OrderType },
    new SO301000Value { Value = "ABARTENDE", LinkedCommand = schema.OrderSummary.CustomerID },
    schema.Actions.Save
};
var result = soapClient.Submit(commands);
soapClient.Logout();

Verify: Log into Acumatica UI and confirm the new order appears on SO301000.

Code Examples

Python: REST API CRUD Operations

# Input:  Acumatica instance URL, OAuth credentials
# Output: Stock item created and queried

import requests

base_url = "https://your-instance.acumatica.com"

# Authenticate via OAuth 2.0
token_resp = requests.post(
    f"{base_url}/identity/connect/token",
    data={
        "grant_type": "password",
        "client_id": "YOUR_CLIENT_ID",
        "client_secret": "YOUR_SECRET",
        "username": "admin",
        "password": "YOUR_PASS",
        "scope": "api"
    }
)
token = token_resp.json()["access_token"]
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}

# Create a stock item (PUT for upsert)
item = {
    "InventoryID": {"value": "PYITEM001"},
    "Description": {"value": "Python-created item"},
    "ItemClass": {"value": "STOCKITEM"}
}
resp = requests.put(f"{base_url}/entity/Default/24.200.001/StockItem", headers=headers, json=item)
print(f"Create: {resp.status_code}")

C#: Screen-Based API Export with PX.Soap.dll

// Input:  Authenticated screen-based SOAP client
// Output: Exported stock items from Inventory screen

var client = new IN202500Screen();
client.Url = "https://your-instance.acumatica.com/Soap/IN202500.asmx";
client.CookieContainer = new System.Net.CookieContainer();
client.Login("admin", "password", "MyCompany", null, null);
try {
    var schema = Helper.GetSchema<IN202500Content>(client);
    var exportCommands = new IN202500Command[] {
        schema.StockItemSummary.InventoryID,
        schema.StockItemSummary.Description,
        schema.StockItemSummary.ItemStatus
    };
    var result = client.Export(exportCommands, null, 0, false, false);
    foreach (var row in result)
        Console.WriteLine($"ID: {row[0]}, Desc: {row[1]}, Status: {row[2]}");
} finally {
    client.Logout();
}

cURL: Quick REST API test

# Input:  Acumatica instance URL, credentials
# Output: Token + entity list

# Get OAuth token
TOKEN=$(curl -s -X POST \
  "https://your-instance.acumatica.com/identity/connect/token" \
  -d "grant_type=password&client_id=YOUR_ID&client_secret=YOUR_SECRET&username=admin&password=YOUR_PASS&scope=api" \
  | jq -r '.access_token')

# List available entities
curl -s "https://your-instance.acumatica.com/entity/Default/24.200.001/" \
  -H "Authorization: Bearer $TOKEN" | jq '.[].name'

Data Mapping

Screen-Based vs REST Field Mapping

Screen-Based Field PathREST API FieldTypeTransformGotcha
OrderSummary.OrderTypeOrderType.valueStringDirectREST wraps values in {value: ...} objects
OrderSummary.CustomerIDCustomerID.valueStringDirectMust match exact customer ID format
DocumentDetails.InventoryIDDetails[].InventoryID.valueStringArray nesting differsScreen-based uses flat commands; REST uses nested JSON arrays
OrderSummary.OrderTotalOrderTotal.valueDecimalDirectRead-only in both APIs (calculated field)
Actions.ReleaseOrderPOST .../SalesOrder/ReleaseOrderActionDifferent invocationScreen-based: include in Submit() commands; REST: separate POST
RowNumber (Export)$skip / $topPaginationDifferent mechanismsScreen-based returns all rows; REST uses OData pagination

Data Type Gotchas

Error Handling & Failure Points

Common Error Codes

CodeMeaningCauseResolution
429Rate limit exceededToo many API requests per minuteExponential backoff; check SM604000 for rate limit
401UnauthorizedExpired/invalid OAuth token or failed Login()Re-authenticate; for screen-based, call Login() again
403ForbiddenUser lacks permissionsCheck API user roles and permissions
500Internal Server ErrorBusiness logic validation failure or server errorCheck Acumatica trace log; common: missing required field
511Data size limit exceededResponse payload too largeAdd $filter and $top to reduce result set
Login limitAPI user session limit reachedAll licensed API user slots in useCall Logout() on idle sessions; increase license count

Failure Points in Production

Anti-Patterns

Wrong: Using screen-based API for standard CRUD in new projects

// BAD - screen-based API for simple CRUD is fragile and verbose
var client = new AR303000Screen();
client.Login(user, pass, company, null, null);
var schema = Helper.GetSchema<AR303000Content>(client);
// Breaks if AR303000 form layout changes in next Acumatica version

Correct: Use REST API for standard CRUD

# GOOD - REST API is decoupled from UI, stable across versions
resp = requests.get(
    f"{base_url}/entity/Default/24.200.001/Customer?$top=100",
    headers={"Authorization": f"Bearer {token}"}
)

Wrong: Forgetting to call Logout()

// BAD - session leak exhausts API user license slots
var client = new SO301000Screen();
client.Login(user, pass, company, null, null);
var result = client.Export(commands, null, 0, false, false);
// No Logout() - session stays open until timeout!

Correct: Always wrap in try/finally with Logout()

// GOOD - guaranteed session release
var client = new SO301000Screen();
client.Login(user, pass, company, null, null);
try {
    var result = client.Export(commands, null, 0, false, false);
} finally {
    client.Logout();
}

Wrong: Hardcoding old endpoint versions

# BAD - version 17.200.001 was removed in 2023 R2
resp = requests.get(f"{base_url}/entity/Default/17.200.001/Customer")

Correct: Centralize version config

# GOOD - centralized, easy to update on upgrade
API_VERSION = "24.200.001"
resp = requests.get(f"{base_url}/entity/Default/{API_VERSION}/Customer", headers=headers)

Common Pitfalls

Diagnostic Commands

# Check available REST API endpoints and versions
curl -s "https://your-instance.acumatica.com/entity/" \
  -H "Authorization: Bearer $TOKEN" | jq .

# List all entities on the Default endpoint
curl -s "https://your-instance.acumatica.com/entity/Default/24.200.001/" \
  -H "Authorization: Bearer $TOKEN" | jq '.[].name'

# Test authentication
curl -s -o /dev/null -w "%{http_code}" \
  "https://your-instance.acumatica.com/entity/Default/24.200.001/" \
  -H "Authorization: Bearer $TOKEN"

# Check screen-based WSDL availability
curl -s "https://your-instance.acumatica.com/Soap/SO301000.asmx?WSDL" | head -20

# Check API user licensing: navigate to SM604000 in Acumatica UI
# Review: Maximum Web Services API Users
# Review: Current API User Sessions

Version History & Compatibility

API Version / ReleaseRelease DateStatusBreaking ChangesMigration Notes
2024 R2 (24.200)2024-10CurrentNew OData URLs introducedLegacy OData URLs supported until 2025 R2
2024 R1 (24.100)2024-04SupportedNone--
2023 R2 (23.200)2023-10SupportedContract-based SOAP removedMigrate to REST. Screen-based SOAP not affected.
2023 R1 (23.100)2023-04SupportedNoneLast version with contract-based SOAP
2021 R2 (21.200)2021-08EOLODBC removedUse OData or REST API instead
5.3 (2016)2016EOLN/AContract-based API first introduced

When to Use / When Not to Use

Use WhenDon't Use WhenUse Instead
Need to automate a processing screen action not exposed via RESTBuilding a new standard CRUD integrationContract-based REST API
Maintaining an existing screen-based integration that worksStarting a greenfield integration projectContract-based REST API
Need to interact with every field on a form as a user wouldOnly need to read/write business objectsContract-based REST API or OData
Client is .NET and can use PX.Soap.dll wrapperClient is Python, JavaScript, Java, or non-.NETContract-based REST API
Need Export() for bulk data extraction from a specific screenNeed BI/reporting data accessOData (GI-based or DAC-based)

Important Caveats

Related Units