P21 API Selection Guide

Disclaimer: This is unofficial, community-created documentation for Epicor Prophet 21 APIs. It is not affiliated with, endorsed by, or supported by Epicor Software Corporation. All product names, trademarks, and registered trademarks are property of their respective owners. Use at your own risk.


Overview

Prophet 21 provides several APIs for external data access and manipulation. This guide helps you choose the right API for your use case.

Quick Decision Table

Need Best API Why
Read data quickly OData Standard protocol, efficient queries
Bulk create records Transaction API Stateless, supports batching
Complex business workflows Interactive API Full business logic, validation
Simple CRUD (customers, vendors, contacts, addresses) Entity API Stateless, domain objects
CRUD on inventory items and locations (inv_loc) Inventory REST API Stateless GET → modify → PUT
Write to user-defined tables (udt_*) UDT Service API Stateless insert/update/delete; read via OData
Update existing records (keyed fields) Transaction API Status: "New" + keyed rows updates and upserts (verified)
Update records behind dialogs/prompts Interactive API Only API that can answer response windows
Handle response dialogs Interactive API Only API with dialog handling
Record labor hours to production orders Transaction API TimeEntry service, stateless
Bulk create production orders Transaction API Stateless, high-volume creation
Modify or complete production orders Interactive API Stateful workflow with validation

API Comparison

Feature OData Transaction Interactive Entity Inventory REST UDT Service
Read Data Excellent Limited Good Good (4 entities) Good (items) No (use OData)
Create Data No Excellent Good Good (4 entities) Good (items) Good (UDT rows)
Update Data No Good* Excellent Good (4 entities) Good (items/locations) Good (by row_uid)
Delete Data No No Via UI Via flag No Yes
Bulk Operations Yes (read) Yes No No No Yes (multi-row insert)
Business Logic No Partial Full No Partial (validation) No
Session Required No No Yes No No No
Stateful No No Yes No No No
Response Dialogs N/A N/A Yes N/A N/A N/A

Transaction API updates use Status: "New" with keyed rows (there is no working "Existing" status — it returns HTTP 500). Keyed rows behave as an upsert*: update if the key matches, insert if it doesn't. Verified at scale (170+ line updates, 80+ line inserts on JobContractPricing). See Updating an Existing Contract. Flows that pop validation dialogs still need the Interactive API.


OData API

Best For

Characteristics

Use When

Don't Use When

Example Use Cases


Transaction API

Best For

Characteristics

Use When

Don't Use When

Known Issues

Example Use Cases


Interactive API

Best For

Characteristics

Use When

Don't Use When

Performance Note

The Interactive API is slower than the Transaction API (~5s vs 0.05s per created record; a windowed edit typically takes ~5 round-trips). Prefer the Transaction API when a keyed update works, and fall back to the Interactive API when the flow needs real window logic or dialog answers.

Version Note

Some P21 servers only support v2 Interactive API endpoints. If you receive 404 errors on /api/ui/interactive/v1/* endpoints, use /api/ui/interactive/v2/* instead. The v2 endpoints have different payload formats - see Interactive API v1 vs v2.

Example Use Cases


Entity API

Best For

Characteristics

Use When

Don't Use When

Example Use Cases


Inventory REST API

Best For

Characteristics

Use When

Don't Use When

Example Use Cases

See Inventory REST API for full details.


UDT Service API

Best For

Characteristics

Use When

Don't Use When

Example Use Cases

See UDT Service API for full details.


Decision Flowchart

Start
  │
  ├─ Need to READ data only?
  │   │
  │   └─ Yes → Use OData API
  │
  ├─ Writing to a user-defined table (udt_*)?
  │   │
  │   └─ Yes → Use UDT Service API
  │
  ├─ CRUD on inventory items / inv_loc?
  │   │
  │   └─ Yes → Use Inventory REST API
  │
  ├─ Need to CREATE multiple records?
  │   │
  │   └─ Yes → Use Transaction API
  │
  ├─ Need to UPDATE records?
  │   │
  │   ├─ Keyed fields/rows, no dialogs → Use Transaction API (Status "New")
  │   │
  │   └─ Dialogs, disabled tabs, complex flows → Use Interactive API
  │
  ├─ Need response dialog handling?
  │   │
  │   └─ Yes → Use Interactive API
  │
  └─ Single-record CREATE?
      │
      ├─ High volume → Use Transaction API
      │
      └─ Low volume / needs validation → Use Interactive API

Hybrid Approaches

Read with OData, Write with Transaction/Interactive

The most common pattern: 1. Use OData for all reads (fast, simple) 2. Use Transaction API for creates and keyed updates (fast) 3. Use Interactive API for flows that need window logic or dialog answers

Example: Price Page Management

# Read existing pages - OData (fast)
pages = odata.get_price_pages(supplier_id=10050)

# Create new pages - Transaction API (bulk, fast)
new_pages = transaction.create_pages([...])

# Update existing page - Interactive API (reliable)
with interactive.open_window("SalesPricePage") as window:
    window.change_data("calculation_value1", "0.55")
    window.save()
// Read existing pages - OData (fast)
var pages = await client.OData.QueryAsync("sales_price_page",
    filter: "supplier_id eq 10050");

// Create new pages - Transaction API (bulk, fast)
var result = await client.Transaction.CreateAsync(newPagesPayload);

// Update existing page - Interactive API (reliable)
await using var session = client.Interactive.CreateSession();
await session.StartAsync();
var window = await session.OpenWindowAsync("SalesPricePage");
await window.ChangeDataAsync("FORM", "calculation_value1", "0.55",
    datawindowName: "form");
await window.SaveDataAsync();
await window.CloseAsync();

Performance Benchmarks

Measured against production P21 instance:

Operation OData Transaction Interactive
Read 160 records 0.12s N/A ~2s
Create 1 record N/A 0.05s 2.5s
Create 25 records N/A 1.4s 62s
Update 1 record N/A ~0.8s* 2.0s

*Transaction API keyed update via Status: "New" (verified on JobContractPricing; per-line latency ~0.8s). Flows that trip prompts or disabled tabs still need the Interactive API.