Acumatica REST API Cookbook
Accumulated patterns, quirks, and solutions from production Acumatica integrations.
Authentication
Session-Based Auth
POST /entity/auth/login
Content-Type: application/json
{
"name": "api-bot",
"password": "...",
"company": "TenantName"
}
Returns HTTP 204 on success (not 200). Extract Set-Cookie headers for the session.
Session cookies expire after 20 minutes. Refresh proactively in long-running workers.
Concurrent Session Limit
Acumatica licenses limit concurrent API sessions (~2-3). Use a session gate pattern:
- Redis sorted set tracks active sessions
- Each service acquires a slot before authenticating
- Slots released on logout or TTL expiry
- Graceful degradation: local semaphore if Redis is unavailable
Entity Operations
PUT for Create AND Update
Acumatica uses PUT for both create and update (upsert pattern). POST to entity endpoints returns HTTP 406 (Not Acceptable).
# Correct: PUT for both create and update
PUT /entity/default/24.200.001/Customer
# Wrong: POST returns 406
POST /entity/default/24.200.001/Customer
Value Wrapper Pattern
All field values are wrapped in {value: x} objects:
{
"CustomerName": {"value": "ACME Corp"},
"Status": {"value": "Active"},
"CreditLimit": {"value": 50000}
}
Read values by unwrapping: record.CustomerName.value
Schema Endpoint
GET /entity/default/24.200.001/{Entity}/$adHocSchema
Returns the full field template including custom fields with type metadata. This is the definitive way to verify custom fields exist after a customization publish.
OData Query Patterns
Basic Query
GET /entity/default/24.200.001/Customer?$top=10&$filter=Status eq 'Active'
Expanding Sub-Entities
GET /entity/default/24.200.001/Customer/C000004?$expand=MainContact,CreditVerificationRules,Salespersons
$expand works on individual record GETs but may return empty on list queries. Some sub-entities (CreditVerificationRules, Attributes) are unreliable in list context.
Nested Expand Not Supported
# Wrong: nested $expand syntax
$expand=WarehouseDetails($select=WarehouseID)
# Correct: simple $expand
$expand=WarehouseDetails
Filtering Limitations
- Custom attributes (e.g.,
AttributeWAYFAIRCON) cannot be used in$filter— throws KeyNotFoundException $select=customcauses 500 errors — use$adHocSchemato inspect custom fields- The
notefield is auto-included in responses but not a filterable property
Custom Fields
Custom Fields vs Attributes
| Feature | Custom Fields (DAC UDF) | Attributes |
|---|---|---|
| Created via | Customization project (C# code) | CS205000 (UI, no code) |
| Appears in | custom.{ViewName}.{FieldName} | Attributes[] array |
| Queryable | In $adHocSchema | With $expand=Attributes on individual GETs |
| List queries | May show in custom section | Empty on list queries |
| Best for | Business logic, computed fields | Simple data storage, dedup keys |
Writing Attributes
PUT /entity/default/24.200.001/StockItem/00004
{
"Attributes": [
{
"AttributeID": {"value": "HUBSPOTPID"},
"Value": {"value": "12345678"}
}
]
}
Entity Name Gotchas
| Expected Name | Actual API Name | Notes |
|---|---|---|
| InventoryItem | StockItem | 404 if you use InventoryItem |
| InventoryAllocationDetail | N/A | Inquiry entity — not in REST API |
| Attribute | N/A | Not exposed — use UI (CS205000) |
Common Error Patterns
| Error | Cause | Fix |
|---|---|---|
| HTTP 406 | Using POST for entity CRUD | Use PUT |
| HTTP 401 | Session expired | Re-authenticate |
HTTP 500 with $select=custom | Known Acumatica bug | Use $adHocSchema instead |
| KeyNotFoundException on filter | Filtering by custom attribute | Use date-based or standard field filters |
| Account locked | Too many concurrent sessions | Wait 15 min or unlock in SM201010 |