Epicor Service Connect (ESC) is the built-in integration middleware for Epicor Kinetic (formerly Epicor ERP 10). It provides a visual Workflow Designer for building data transformation and orchestration flows without extensive custom code. ESC operates as a Windows service and processes messages through configurable input/output channels. Available for on-premise and hybrid deployments; cloud SaaS deployments may have restricted ESC access. As of Kinetic 2023.2, Epicor also offers Data Fabric (Kafka-based) as a cloud-native alternative. [src1, src2]
| Property | Value |
|---|---|
| Vendor | Epicor |
| System | Epicor Kinetic (Service Connect 10.2.x) |
| API Surface | SOAP, REST (v1/v2), .NET Assemblies, XML Web Services |
| Current Version | Kinetic 2024.x / ESC 10.2.700+ |
| Editions Covered | All Epicor Kinetic editions with Service Connect license add-on |
| Deployment | On-Premise / Hybrid (limited in SaaS) |
| API Docs | Epicor Service Connect (instance-specific REST help at /apps/resthelp/) |
| Status | GA (actively maintained) |
ESC interacts with Epicor and external systems through multiple API surfaces. The primary method is .NET Reference calls to Epicor business objects within ESC workflows, while REST and SOAP APIs provide alternative access paths for external integrations. [src1, src4]
| API Surface | Protocol | Best For | Max Records/Request | Rate Limit | Real-time? | Bulk? |
|---|---|---|---|---|---|---|
| .NET Reference (BO calls) | .NET Assembly | Direct Epicor BO operations within ESC workflows | Transaction-dependent | No explicit limit | Yes | No |
| REST API v2 | HTTPS/JSON+OData | External integrations, mobile/web apps | $top/$skip pagination (default 100) | None built-in (IIS-configured) | Yes | Via batch |
| SOAP/WCF Services | HTTPS/XML | Legacy integrations, .NET clients | 2,000+ per query | None built-in | Yes | No |
| ESC Web Service Endpoint | HTTPS/XML | Exposing ESC workflows as callable services | Per-workflow | N/A | Yes | No |
| File Channel (CSV/XML/Excel) | File system | Scheduled batch imports/exports | File size limited by memory | N/A | No | Yes |
| FTP/Email Channel | FTP/SMTP | Remote file pickup, email-triggered workflows | File/message size | N/A | No | Yes |
| MSMQ Channel | MSMQ | Reliable queued messaging | 4 MB default message size | Queue depth | Yes | No |
| Limit Type | Value | Applies To | Notes |
|---|---|---|---|
| REST API default page size | 100 records | REST API v2 OData queries | Use $top and $skip for pagination [src4] |
| REST API request body | Server-configured | REST API POST/PATCH | IIS maxAllowedContentLength (default 28.6 MB) |
| MSMQ message size | 4 MB default | MSMQ channel | Configurable via MSMQ settings on server |
| File channel file size | Memory-bound | CSV/XML/Excel imports | Large files (>50 MB) may cause OutOfMemoryException |
| $batch subrequests | Server-configured | REST API v2 batch | IIS request limits apply |
| Limit Type | Value | Window | Edition Differences |
|---|---|---|---|
| REST API calls | No built-in limit | N/A | Must configure via IIS Dynamic IP Restrictions or reverse proxy [src5] |
| Concurrent REST sessions | IIS AppPool worker threads | Per-AppPool | Default: 25 worker threads per AppPool |
| ESC concurrent workflows | Thread pool-dependent | Per ESC service instance | Default configurable in ESC admin; typically 5-20 concurrent |
| Web Service license seats | License-dependent | Per-org | Exhaustion causes progressive response time degradation [src5] |
| Flow | Use When | Token Lifetime | Refresh? | Notes |
|---|---|---|---|---|
| Basic Authentication | Simple REST API integrations, testing | Per-request (stateless) | N/A | Base64 username:password. Most common for ESC REST calls. [src4] |
| OAuth 2.0 (ROPC) | Production REST integrations | ~20 min (configurable) | Yes (refresh token) | POST to /Token endpoint with grant_type=password. [src4] |
| API Key (REST v2) | Programmatic access | Persistent until revoked | N/A | Configured per-user in Epicor Admin Console. REST v2 only. [src4] |
| Epicor Session (.NET) | ESC internal BO calls | Session duration | Automatic | Dedicated service account required. [src3] |
| Windows Authentication | On-premise intranet | Windows session | N/A | IIS-level SSO for domain-joined clients |
START -- Integrate with Epicor Kinetic
|-- What is the integration surface?
| |-- Service Connect (ESC) workflow orchestration
| | |-- Data source format?
| | | |-- XML --> Direct input channel (File, FTP, MSMQ, Web Service)
| | | |-- CSV/Excel/Fixed-width --> Conversion Map + File channel
| | | |-- Database --> dbLookup functoid within workflow
| | | |-- Epicor BO call --> .NET Reference activity
| | |-- Integration trigger?
| | | |-- Scheduled --> File channel with folder polling
| | | |-- Event-driven --> BPM directive triggers ESC workflow
| | | |-- On-demand --> Expose workflow as Web Service endpoint
| | | |-- Queue-based --> MSMQ channel for reliable delivery
| | |-- Error handling approach?
| | |-- Simple notification --> Choice + Poster (email) [src3]
| | |-- UD table logging --> Choice + UpdateExt to UD table [src3]
| | |-- Full reprocessing --> Log all fields to UD + errors [src3]
| |-- Direct REST API (bypass ESC)
| | |-- Volume < 1,000 records/day --> REST API v2 + Basic Auth/API Key
| | |-- Volume > 1,000 records/day --> REST API v2 + batch + IIS throttle
| | |-- Real-time notifications --> BPM + Epicor Functions + REST callout
| |-- Epicor Data Fabric (Kinetic 2023.2+)
| |-- Cloud-native event streaming --> Apache Kafka via Confluent Cloud
| |-- High-volume real-time CDC --> Data Fabric preferred over ESC
| Workflow Element | Type | Purpose | Notes |
|---|---|---|---|
| .NET Reference | Activity | Call Epicor BO methods (GetNew, Update, GetList) | Core activity for all Epicor data operations [src2] |
| XML Mapper | Activity | Transform XML structure between schemas | Drag-and-drop field mapping with functoid support [src2] |
| Choice | Control Flow | Conditional branching / error checking | Essential after every .NET Reference call [src3] |
| Poster | Activity | Send email notifications, write to channels | Error notification pattern [src3] |
| dbLookup | Functoid | Query external databases within XML Mapper | Uses ADO.NET; connection string required [src2] |
| Conversion Map | Activity | Convert non-XML formats to XML | Required for CSV/Excel/fixed-width imports |
| Scheduler | Configuration | Time-based workflow triggers | Cron-style scheduling within ESC admin |
| Human Workflow | Activity | User task assignment with email | Approval-based integration flows [src1] |
| Web Service Endpoint | Channel | Expose workflow as callable SOAP service | External systems invoke via WSDL |
| File Drop Channel | Channel | Monitor folder for new files | UNC paths supported; configurable polling interval |
| FTP Channel | Channel | Monitor FTP/SFTP for files | EDI and partner data exchange [src1] |
| MSMQ Channel | Channel | Microsoft Message Queue integration | Transactional delivery; survives ESC restart |
| Email Channel | Channel | Process inbound emails/attachments | Email-triggered workflows |
| COM Channel | Channel | COM-based application interaction | Legacy; rarely used in modern integrations |
Create a dedicated Epicor user for ESC that will never be used for interactive logins. Assign appropriate security groups. [src3]
Epicor Admin steps:
1. Go to System Setup > Security Maintenance > User Account Maintenance
2. Create user: "ESC_SvcAcct" with strong password
3. Assign to security groups covering required BO access
4. Set default plant, company, and site context
5. NEVER log in interactively with this account
6. Configure ESC service to use these credentials
Verify: Log in to ESC Administration Console and confirm the service account can connect to the Epicor application server.
Open the Workflow Designer, create a new Workflow Package, then configure an input channel for your data source. [src2]
Workflow Designer steps:
1. Right-click Workflow Packages > New Package > name: "SalesOrderImport"
2. Right-click package > New Workflow > name: "ImportSalesOrders"
3. Configure Input Channel:
- Type: File Drop
- Path: \\server\share\incoming\sales_orders\
- File Pattern: *.xml (or *.csv with conversion map)
- Polling Interval: 60 seconds
4. If CSV: Add Conversion Map activity to convert CSV to XML
Verify: Drop a test file in the monitored folder and confirm ESC picks it up via Workflow Monitor.
Drag .NET Reference activities onto the workflow canvas. Browse to target Epicor business objects and map fields via XML Mapper. [src2, src4]
.NET Reference configuration:
1. Drag ".NET Reference" activity to workflow canvas
2. Browse Assembly: Erp.Contracts.BO.SalesOrder.dll
3. Select Method: GetNewOrderHed
4. Open XML Mapper: drag source XML fields to target BO dataset fields
5. Add second .NET Reference: SalesOrderSvc.Update
6. Map all required fields (CustNum, OrderDate, OrderLines, etc.)
Verify: Right-click the .NET Reference activity > Test with sample data. Check Epicor for created records.
After every .NET Reference call, add a Choice element to check for errors. Branch to error handling (email, UD table, or both). [src3]
Error handling pattern:
1. After each .NET Reference, add Choice element
2. Condition: Check callContext.ExceptionMessage != ""
- TRUE branch: Error occurred
- Option A: Poster (email to admin) -- simplest
- Option B: .NET Reference to UD table (UpdateExt) -- queryable audit trail
- Option C: Log all input fields + error details -- enables re-run
- FALSE branch: Continue to next step
Verify: Send malformed data deliberately. Confirm error notification received and/or UD table entry created.
# Input: Epicor server URL, credentials, business object name
# Output: JSON array of records from Epicor
import requests
from requests.auth import HTTPBasicAuth
server = "https://epicor-server/ERP_Instance"
username = "ESC_SvcAcct"
password = "YourSecurePassword"
url = f"{server}/api/v2/odata/Erp.BO.SalesOrderSvc/SalesOrderHeds"
params = {
"$filter": "OrderHeld eq false",
"$select": "OrderNum,CustNum,OrderDate,OrderTotal",
"$top": 50,
"$orderby": "OrderDate desc"
}
response = requests.get(
url, params=params,
auth=HTTPBasicAuth(username, password),
headers={"Accept": "application/json"}
)
if response.status_code == 200:
data = response.json()
for order in data.get("value", []):
print(f"Order {order['OrderNum']}: ${order['OrderTotal']}")
elif response.status_code == 401:
print("Authentication failed - check credentials")
else:
print(f"Error {response.status_code}: {response.text}")
// Input: Epicor server URL, credentials, customer number
// Output: Created sales order number
const fetch = require("node-fetch"); // npm install node-fetch@2
const server = "https://epicor-server/ERP_Instance";
const credentials = Buffer.from("username:password").toString("base64");
async function createSalesOrder(custNum) {
const getNewResp = await fetch(
`${server}/api/v2/odata/Erp.BO.SalesOrderSvc/GetNewOrderHed`,
{
method: "POST",
headers: {
Authorization: `Basic ${credentials}`,
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({ ds: {} }),
}
);
if (!getNewResp.ok) throw new Error(`GetNewOrderHed: ${getNewResp.status}`);
const ds = await getNewResp.json();
ds.parameters.ds.OrderHed[0].CustNum = custNum;
const updateResp = await fetch(
`${server}/api/v2/odata/Erp.BO.SalesOrderSvc/Update`,
{
method: "POST",
headers: {
Authorization: `Basic ${credentials}`,
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({ ds: ds.parameters.ds }),
}
);
if (!updateResp.ok) throw new Error(`Update: ${updateResp.status}`);
const result = await updateResp.json();
console.log("Created Order:", result.parameters.ds.OrderHed[0].OrderNum);
}
createSalesOrder(1234).catch(console.error);
# Input: Epicor server URL, credentials
# Output: JSON response from business object query
# Test Basic Auth connectivity
curl -s -X GET \
"https://epicor-server/ERP_Instance/api/v2/odata/Erp.BO.SalesOrderSvc/SalesOrderHeds?\$top=5" \
-H "Authorization: Basic $(echo -n 'username:password' | base64)" \
-H "Accept: application/json" | jq .
# Test OAuth token acquisition
curl -s -X POST \
"https://epicor-server/ERP_Instance/Token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password&username=ESC_SvcAcct&password=YourPassword" | jq .
| Epicor Field | REST API Path | Type | Transform | Gotcha |
|---|---|---|---|---|
| OrderHed.OrderNum | SalesOrderHeds(OrderNum) | Int | Auto-assigned | Read-only after creation |
| OrderHed.CustNum | SalesOrderHeds.CustNum | Int | Direct | Must exist in Customer table |
| OrderHed.OrderDate | SalesOrderHeds.OrderDate | DateTime | ISO 8601 | REST: 2026-03-02T00:00:00; ESC XML: .NET DateTime |
| OrderDtl.PartNum | SalesOrderDtls.PartNum | String | Direct | Max 50 chars; must exist in Part table |
| OrderDtl.OrderQty | SalesOrderDtls.OrderQty | Decimal | Direct | Precision depends on UOM setup |
| Customer.Name | Customers.Name | String | Direct | Max 50 chars in Epicor |
| JobHead.JobNum | JobHeads.JobNum | String | Direct | Max 14 chars; alphanumeric only |
| Code | Meaning | Cause | Resolution |
|---|---|---|---|
| BPM Exception | Business logic violation | BPM rule prevents operation | Check BPM directives; add pre-validation [src6] |
| "null value" error | Required field missing | Upgrade added new required fields | Compare BO schema pre/post upgrade; update XML Mapper [src7] |
| "Object reference not set" | Null reference | Missing parent record or bad dataset structure | Ensure GetNew called before Update; verify dataset hierarchy |
| 401 Unauthorized | Auth failure | Bad credentials or expired token | Verify username/password; acquire new token [src4] |
| 429 Too Many Requests | IIS rate limit hit | Too many concurrent API calls | Implement backoff; increase IIS limits [src5] |
| "Session limit reached" | License exhaustion | All Web Service license seats consumed | Scale back concurrent workflows; purchase licenses [src5] |
| Timeout | BO method too slow | Large dataset or complex BPM processing | Increase WCF timeout; break into smaller batches |
| MSMQ full | Queue at capacity | Consumer not processing fast enough | Increase MSMQ storage limits; scale ESC threads |
Export all workflow XML mappings before upgrade. Compare BO schemas and update mappings for new required fields. Test every workflow in pilot. [src7]Create a dedicated, never-interactive ESC service account with locked plant/company. [src3]Split large files into 10,000-20,000 record chunks before dropping into ESC monitored folder. [src2]Monitor thread pool usage. Set max concurrent workflows in ESC admin. Break long workflows into sub-workflows. [src2]Check token expiry before each batch. Implement token refresh logic. [src4]<!-- BAD - no error check; failures are silent -->
<NetReference assembly="SalesOrderSvc" method="Update" />
<NetReference assembly="SalesOrderSvc" method="GetByID" />
<!-- If Update fails, GetByID runs on stale data -->
<!-- GOOD - error check after every BO call -->
<NetReference assembly="SalesOrderSvc" method="Update" />
<Choice condition="callContext.ExceptionMessage != ''">
<True>
<Poster type="email" to="[email protected]"
subject="ESC Error: SalesOrder Update failed"
body="{callContext.ExceptionMessage}" />
<Stop />
</True>
<False>
<NetReference assembly="SalesOrderSvc" method="GetByID" />
</False>
</Choice>
// BAD - ESC runs as "JSmith" who also uses Epicor desktop client
// When JSmith switches to Plant B, ESC writes data to Plant B instead of Plant A
Service Account: JSmith (also logs in interactively)
// GOOD - dedicated account with locked context
Service Account: ESC_SvcAcct
- Never used for interactive login
- Default Plant: Plant A (locked)
- Default Company: Company01 (locked)
- Security: Only BO permissions needed for workflows
// BAD - 500,000-row CSV into ESC file channel
// ESC converts entire file to XML in memory -> OutOfMemoryException
Input: customers_full_export.csv (500,000 rows, 200 MB)
# GOOD - split large file into 10,000-row chunks
split -l 10000 --additional-suffix=.csv customers_full_export.csv chunk_
for f in chunk_*.csv; do
cp "$f" /epicor/esc/incoming/
sleep 30 # Allow ESC to process each chunk
done
Run every ESC workflow against the upgraded pilot environment before go-live. [src7]Set up daily checks of Workflow Monitor. Configure email alerts for failed workflows. [src1]Use UNC paths and configure them as ESC parameters. [src2]Check for existing records via GetByID or GetList before creating. Use external reference IDs as unique keys. [src3]Always add a Conversion Map as the first activity for non-XML inputs. [src2]Use REST API v2 directly with queuing for high-volume real-time. Reserve ESC for orchestrated multi-step flows. [src5, src6]# Check ESC Windows service status
sc query "EpicorServiceConnect" | findstr STATE
# View ESC service logs (Windows Event Viewer)
wevtutil qe Application /q:"*[System[Provider[@Name='EpicorServiceConnect']]]" /c:20 /f:text
# Test REST API connectivity and authentication
curl -s -X GET \
"https://epicor-server/ERP_Instance/api/v2/odata/Ice.BO.UserFileSvc/UserFiles?\$top=1" \
-H "Authorization: Basic $(echo -n 'username:password' | base64)" \
-H "Accept: application/json" | jq .
# Check IIS AppPool status
%systemroot%\system32\inetsrv\appcmd.exe list apppool "EpicorAppPool" /text:state
# Monitor IIS worker process memory
tasklist /fi "imagename eq w3wp.exe" /v
# Check MSMQ queue depth (if using MSMQ channel)
powershell "Get-MsmqQueue -Name 'EpicorESC*' | Select QueueName, MessageCount"
| Version | Release Date | Status | Breaking Changes | Migration Notes |
|---|---|---|---|---|
| Kinetic 2024.1 | 2024-03 | Current | None for ESC | Field Service Management added; ESC unchanged |
| Kinetic 2023.2 | 2023-09 | Supported | Data Fabric introduced | Kafka-based alternative; ESC still supported |
| Kinetic 2022.2 | 2022-09 | Supported | REST API v2 enhancements | v2 adds API Key auth; OData improvements |
| ERP 10.2.700 | 2021-06 | Supported (legacy) | Rebranded to Kinetic | ESC workflows from 10.2.x forward-compatible |
| ERP 10.2.500 | 2020-03 | EOL | ESC installation changes | New installer; configs migrate automatically |
| ERP 10.2.400 | 2019-06 | EOL | BO dataset schema changes | Review all XML mappings [src7] |
Epicor follows a rolling support model: current release and two prior releases are actively supported. Service Connect continues in Kinetic, though Data Fabric (2023.2+) represents the strategic direction for cloud-native integrations. No announced deprecation date for Service Connect. [src1]
| Use When | Don't Use When | Use Instead |
|---|---|---|
| Multi-step data transformation with conditional logic and error handling | Simple CRUD on single business objects | Epicor REST API v2 direct calls |
| Scheduled file-based imports (CSV, Excel, XML from partners/EDI) | High-volume real-time streaming (>1,000 TPS) | Epicor Data Fabric (Kafka) or REST + message queue |
| BPM-triggered outbound integrations requiring data enrichment | Simple BPM email notifications or field calculations | Epicor BPM directives (no ESC needed) |
| Legacy SOAP/COM integrations with older partner systems | Modern microservices architecture with REST APIs | REST API v2 + iPaaS (MuleSoft, Boomi, Workato) |
| Reliable message-based integration via MSMQ | Cloud-to-cloud SaaS integrations | iPaaS platform or Epicor Data Fabric |