Acumatica Screen-Based API: How It Works and When to Use It vs REST
How does the Acumatica screen-based API work and when should you use it vs REST?
TL;DR
- Bottom line: The Acumatica screen-based API is a SOAP/XML web service that maps directly to ERP form elements, giving access to every screen action and field. Use the contract-based REST API for new integrations; use screen-based only when you need functionality not yet exposed through the contract-based API.
- Key limit: Screen-based API is tightly coupled to UI layouts -- any screen customization (moving a control, changing a form group) can break your integration code and require recompilation.
- Watch out for: Contract-based SOAP endpoints (versions 17.200 and 18.200) were removed in Acumatica 2023 R2, but screen-based SOAP endpoints remain available. Do not confuse the two.
- Best for: Automating screen-specific actions (report generation, processing screens, custom actions) not exposed through the REST API, and maintaining legacy integrations.
- Authentication: OAuth 2.0 (authorization code or resource owner password credentials) or cookie-based session authentication via Login/Logout SOAP methods.
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.
| Property | Value |
|---|---|
| Vendor | Acumatica |
| System | Acumatica ERP 2024 R2 (24.200) |
| API Surface | SOAP (Screen-Based) + REST (Contract-Based) + OData |
| Current API Version | Screen-Based: per-screen WSDL; REST: 24.200.001 |
| Editions Covered | Small Business, Standard, Enterprise |
| Deployment | Cloud / Hosted / On-Premise |
| API Docs | Acumatica Integration Development Guide |
| Status | Screen-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 Surface | Protocol | Best For | Stability | Coverage | Real-time? | Bulk? |
|---|---|---|---|---|---|---|
| Screen-Based SOAP | HTTPS/XML (SOAP) | Automating any screen action, processing screens, legacy | Low - breaks on UI changes | Complete (every form) | Yes | Via Export/Import |
| Contract-Based REST | HTTPS/JSON (REST) | CRUD operations, new integrations, cross-platform | High - decoupled from UI | Partial (configured endpoints) | Yes | Limited |
| Contract-Based SOAP | HTTPS/XML (SOAP) | Legacy contract-based integrations | High - decoupled from UI | Same as REST | Yes | Limited |
| OData (GI-Based) | HTTPS/JSON (OData v4) | BI tools, reporting, read-only | High | Generic Inquiries only | Yes | Read-only |
| OData (DAC-Based) | HTTPS/JSON (OData v4) | Direct DAC access for reporting | High | DAC-exposed entities | Yes | Read-only |
Rate Limits & Quotas
Per-Request Limits
| Limit Type | Value | Applies To | Notes |
|---|---|---|---|
| Max concurrent API user sessions | License-dependent | All API surfaces | Configured on SM604000; exceeding returns login error |
| Request body size | No published hard limit | REST API | Denial Code 511 returned for oversized payloads |
| Export batch size | Configurable per call | Screen-Based Export() | Set via TopCount parameter |
| Composite batch size | 1,000 per $batch | REST API | Each subrequest counts as a separate API call |
Rolling / Daily Limits
| Limit Type | Value | Window | Edition Differences |
|---|---|---|---|
| API requests per minute | License-dependent | Per minute | At 50% of limit, requests are throttled; at 100%, rejected |
| Concurrent API users | License-dependent | Concurrent sessions | Small Business: fewer; Enterprise: more. Check SM604000 |
| Total API calls | No published daily cap | 24h | Governed 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]
| Flow | Use When | Token Lifetime | Refresh? | Notes |
|---|---|---|---|---|
| OAuth 2.0 Authorization Code | Interactive applications, user-context | Configurable | Yes | Register on SM303010 (Connected Applications) |
| OAuth 2.0 Resource Owner Password | Server-to-server integrations | Configurable | Yes | Simpler setup but less secure |
| Cookie-based (Login/Logout SOAP) | Legacy screen-based API integrations | Session-based | No | Uses Login() method with username, password, company, branch |
| OAuth 2.0 Client Credentials | Service-to-service, no user context | Configurable | Yes | Available in newer Acumatica versions |
Authentication Gotchas
- Screen-based Login() counts against API user limit: Each Login() call consumes an API user session slot. Forgetting Logout() can exhaust your licensed API user count. [src4, src6]
- OAuth tokens work for both API surfaces: An access token obtained for REST API can also be used with screen-based SOAP calls via the Authorization header. [src3]
- ODBC connectivity was removed in 2021 R2: All data access must go through APIs or OData. [src5]
Constraints
- Screen-based API is UI-coupled: Any change to a form's layout changes the WSDL and can break compiled client code.
- PX.Soap.dll wrapper requires .NET: Non-.NET clients must work directly with raw SOAP XML.
- Contract-based SOAP endpoints removed in 2023 R2: The 17.200 and 18.200 endpoints were removed. Screen-based SOAP endpoints remain.
- Screen-based API not officially recommended for new development: Acumatica recommends contract-based REST API for all new integrations.
- Not all screen actions are exposed in REST API: Some processing screens and custom actions are only accessible through screen-based API.
- API user sessions are license-limited: Exceeding the licensed API user count blocks new API logins entirely. Check SM604000.
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
| Operation | Screen-Based API | Contract-Based REST API | Notes |
|---|---|---|---|
| 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?WSDL | N/A (OpenAPI via SM207000) | Screen-based generates WSDL per form |
| Create record | Submit() with Content object | PUT /entity/Default/24.200.001/{Entity} | REST uses JSON; screen-based uses SOAP XML |
| Read records | Export() with filters | GET /entity/Default/24.200.001/{Entity}?$filter=... | REST supports OData query syntax |
| Update record | Submit() with modified Content | PUT /entity/Default/24.200.001/{Entity} | Both use record key fields |
| Delete record | Clear() then Submit() | DELETE /entity/Default/24.200.001/{Entity}/{keys} | Screen-based requires clearing then submitting |
| Execute action | Submit() with action trigger | POST .../SalesOrder/ReleaseOrder | Screen-based can trigger any button; REST only configured actions |
| Check async status | GetProcessStatus() | GET .../{Entity}?$longRunning=true | Screen-based has dedicated polling method |
| Login | Login(name, password, company, branch) | OAuth 2.0 Bearer token | Screen-based: session cookie; REST: Authorization header |
| Logout | Logout() | N/A (token expiry) | Screen-based MUST call Logout() to free session |
| Schema discovery | GetSchema() / SetSchema() | /entity/Default/24.200.001 | Screen-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 Path | REST API Field | Type | Transform | Gotcha |
|---|---|---|---|---|
| OrderSummary.OrderType | OrderType.value | String | Direct | REST wraps values in {value: ...} objects |
| OrderSummary.CustomerID | CustomerID.value | String | Direct | Must match exact customer ID format |
| DocumentDetails.InventoryID | Details[].InventoryID.value | String | Array nesting differs | Screen-based uses flat commands; REST uses nested JSON arrays |
| OrderSummary.OrderTotal | OrderTotal.value | Decimal | Direct | Read-only in both APIs (calculated field) |
| Actions.ReleaseOrder | POST .../SalesOrder/ReleaseOrder | Action | Different invocation | Screen-based: include in Submit() commands; REST: separate POST |
| RowNumber (Export) | $skip / $top | Pagination | Different mechanisms | Screen-based returns all rows; REST uses OData pagination |
Data Type Gotchas
- REST API wraps all values in objects: Every field is
{"value": actual_value}. Failing to wrap values returns validation errors. [src3] - Date formats differ: Screen-based uses .NET DateTime; REST uses ISO 8601. [src3, src4]
- Custom fields need explicit REST endpoint configuration on SM207000 before they are accessible via REST. [src7]
Error Handling & Failure Points
Common Error Codes
| Code | Meaning | Cause | Resolution |
|---|---|---|---|
| 429 | Rate limit exceeded | Too many API requests per minute | Exponential backoff; check SM604000 for rate limit |
| 401 | Unauthorized | Expired/invalid OAuth token or failed Login() | Re-authenticate; for screen-based, call Login() again |
| 403 | Forbidden | User lacks permissions | Check API user roles and permissions |
| 500 | Internal Server Error | Business logic validation failure or server error | Check Acumatica trace log; common: missing required field |
| 511 | Data size limit exceeded | Response payload too large | Add $filter and $top to reduce result set |
| Login limit | API user session limit reached | All licensed API user slots in use | Call Logout() on idle sessions; increase license count |
Failure Points in Production
- Session leak on screen-based API: Login() called but Logout() never called. Fix:
Wrap all screen-based API calls in try/finally blocks. Always call Logout() in finally.[src4, src6] - Schema cache stale after upgrade: PX.Soap.dll caches schemas locally; after upgrade, cached schema becomes stale. Fix:
Delete locally cached schema files after each Acumatica upgrade.[src4] - REST endpoint version mismatch: Old endpoint version (e.g., 17.200.001) removed causes 404. Fix:
Always use latest endpoint version. Update version number after each Acumatica upgrade.[src2, src7] - Rate throttling cascade delays: At 50% of limit, requests are delayed, causing timeouts. Fix:
Set HTTP client timeouts higher. Implement retry with exponential backoff.[src6] - Custom field not visible in REST API: Adding a custom field to a screen does not expose it via REST. Fix:
Add the field to endpoint mapping on SM207000.[src7]
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
- Confusing contract-based SOAP with screen-based SOAP: Two different SOAP APIs. Contract-based SOAP (17.200, 18.200) removed in 2023 R2; screen-based SOAP (/Soap/{FormID}.asmx) remains. Fix:
Check which SOAP type your integration uses. /entity/ URLs = contract-based (migrate to REST). /Soap/{FormID}.asmx = screen-based (still supported).[src2] - Not configuring custom endpoints for REST API: The Default endpoint only exposes standard entities. Fix:
Review SM207000 before starting REST development. Create custom endpoints for non-standard entities.[src7] - Ignoring push notifications for change tracking: Polling wastes API calls and hits rate limits. Fix:
Configure Push Notifications on SM302000 to trigger webhooks on record changes.[src3] - Using Export() without TopCount for large datasets: Causes timeouts and memory issues. Fix:
Always set TopCount parameter and implement pagination.[src4] - Testing with admin, deploying with restricted API user: Everything works in dev; production returns 403. Fix:
Test with the actual API user account in staging.[src6] - Not handling the value wrapper in REST responses: REST returns
{"value": "data"}objects, not bare values. Fix:Define proper DTOs or use Acumatica's official REST client from GitHub.[src3]
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 / Release | Release Date | Status | Breaking Changes | Migration Notes |
|---|---|---|---|---|
| 2024 R2 (24.200) | 2024-10 | Current | New OData URLs introduced | Legacy OData URLs supported until 2025 R2 |
| 2024 R1 (24.100) | 2024-04 | Supported | None | -- |
| 2023 R2 (23.200) | 2023-10 | Supported | Contract-based SOAP removed | Migrate to REST. Screen-based SOAP not affected. |
| 2023 R1 (23.100) | 2023-04 | Supported | None | Last version with contract-based SOAP |
| 2021 R2 (21.200) | 2021-08 | EOL | ODBC removed | Use OData or REST API instead |
| 5.3 (2016) | 2016 | EOL | N/A | Contract-based API first introduced |
When to Use / When Not to Use
| Use When | Don't Use When | Use Instead |
|---|---|---|
| Need to automate a processing screen action not exposed via REST | Building a new standard CRUD integration | Contract-based REST API |
| Maintaining an existing screen-based integration that works | Starting a greenfield integration project | Contract-based REST API |
| Need to interact with every field on a form as a user would | Only need to read/write business objects | Contract-based REST API or OData |
| Client is .NET and can use PX.Soap.dll wrapper | Client is Python, JavaScript, Java, or non-.NET | Contract-based REST API |
| Need Export() for bulk data extraction from a specific screen | Need BI/reporting data access | OData (GI-based or DAC-based) |
Important Caveats
- The screen-based API has no announced end-of-life date, but Acumatica is investing exclusively in the REST API for new features. Plan migrations accordingly.
- Rate limits and API user session limits are license-dependent with no published universal numbers. Always check SM604000 in your specific instance.
- Screen-based SOAP and contract-based SOAP are two completely different APIs. The removal of contract-based SOAP in 2023 R2 does NOT affect screen-based SOAP.
- The PX.Soap.dll wrapper caches form schemas locally. After any upgrade that modifies screens, clear cached schemas or integrations may reference outdated field paths.
- Push notifications and webhooks (SM302000, SM304000) are the recommended event-driven pattern. Do not poll the API for changes.