Sage X3 SOAP Web Services: Architecture, Operations, and Limitations

Type: ERP Integration System: Sage X3 (Enterprise Management) (V12 PU9+) Confidence: 0.88 Sources: 8 Verified: 2026-03-02 Freshness: 2026-03-02

TL;DR

System Profile

Sage X3 (also known as Sage Enterprise Management) is a mid-market ERP system that exposes its business logic through SOAP web services. The SOAP interface has been available since V6 and remains the primary mechanism for write operations on classic modules - the REST/SData 2.0 Web API provides read-only access to classic module data. This card covers the SOAP web services architecture in V12 (PU9 and later), which introduced significant changes to endpoint URLs, authentication, and pool management. [src1, src2, src4]

PropertyValue
VendorSage
SystemSage X3 (Enterprise Management) V12
API SurfaceSOAP (RPC/encoded), via CAdxWebServiceXmlCC
Current API VersionV12 (PU9+)
Editions CoveredStandard, Premium (all editions)
DeploymentHybrid (on-premise and Sage X3 Online/cloud)
API DocsSage X3 SOAP Web Services
StatusGA (maintenance - Sage migrating to REST/SData 2.0)

API Surfaces & Capabilities

Sage X3 offers two primary API surfaces. SOAP is the mature, full-featured option for classic modules. REST (SData 2.0) is the modern successor, but only supports write operations on service-oriented (migrated) modules. [src1, src2]

API SurfaceProtocolBest ForOperationsRate LimitReal-time?Bulk?
SOAP (CAdxWebServiceXmlCC)HTTPS/XML (RPC/encoded)Write operations on classic objects, subprogram executionCRUD, query, import, export, subprogramLicense-based (WSSIZELIMIT MB/period)YesVia import/export
REST Web API (SData 2.0)HTTPS/JSONRead operations on all modules, write on service-oriented modulesGET, POST, PUT, DELETELicense-basedYesNo native bulk
SOAP Import/ExportHTTPS/XMLFile-based batch data exchangeAOWSIMPORT, AOWSEXPORTShared with SOAP limitNo (batch)Yes

Rate Limits & Quotas

Per-Request Limits

Limit TypeValueApplies ToNotes
Max records per query (listSize)Configurable per callSOAP query operationsSet via listSize parameter; no hard system maximum documented
Max pool clients per node.js processConfigured via Maximum SizeSOAP poolTypical range: 2-10 clients per pool
Unused client timeout20 min (default)Individual pool clientIdle clients are automatically stopped after this period
Client life timeout720 min / 12 hours (default)Individual pool clientChannels reset after this duration regardless of activity

Rolling / Daily Limits

Limit TypeValueWindowEdition Differences
Data volume (WSSIZELIMIT)License-dependent (MB)DAY, MONTH, or YEAR (WSPERIOD)Varies by license tier; not publicly documented per-edition
Grace overage (WSGRACELIMIT)Typically 10% above WSSIZELIMITSame as WSPERIODCalls continue but speed degrades
Throttle factor (WSGRACESLOWDOWN)Speed divided by configured factor (e.g., 5x)Until period resetsWhen daily limit reached, speed divided by 5 until end of day

Concurrency Limits

Limit TypeValueNotes
Pool initialization sizeConfigurable (e.g., 2)Clients created at pool startup per node.js process
Pool maximum sizeConfigurable (e.g., 4-10)Maximum concurrent clients per node.js process
Web service child processes>= 1 required on hostSet via Administration > Servers > Hosts; 0 = HTTP 500 errors
Initialization size limitAvoid > 8Setting initialization size above 8 may cause timeout errors during pool start/stop

Authentication

Sage X3 SOAP web services support three authentication mechanisms, with availability depending on deployment model. [src2]

FlowUse WhenDeploymentCredential StorageNotes
Basic Authentication (HTTP)On-premise integrations, simplest setupOn-premise onlyUsername/password in HTTP Authorization headerPU9+ moved auth from SOAP context to HTTP headers. Password must be set to never expire. [src4, src5]
Certificate AuthenticationOn-premise production environmentsOn-premise onlyX.509 certificateSSL client certificate presented with each request
OAuth 2.0Sage X3 Online (cloud) - mandatoryCloud onlyBearer token in Authorization headerOnly method available in Sage X3 Online; configure via Sage ID [src2]

Authentication Gotchas

Constraints

Integration Pattern Decision Tree

START - User needs to integrate with Sage X3
|-- What operations are needed?
|   |-- Read-only data access
|   |   |-- Module is service-oriented (migrated)?
|   |   |   |-- YES --> Use REST/SData 2.0 Web API (simpler, JSON, modern)
|   |   |   |-- NO --> REST provides read-only representations; sufficient for reads
|   |   |-- Need complex queries with criteria?
|   |       |-- YES --> SOAP query with listSize and criteria parameters
|   |       |-- NO --> REST GET with $filter is simpler
|   |-- Write operations (create, modify, delete)
|   |   |-- Module is service-oriented?
|   |   |   |-- YES --> REST POST/PUT/DELETE available
|   |   |   |-- NO --> SOAP is required (only write path for classic modules)
|   |-- Batch import/export
|   |   --> SOAP import/export (AOWSIMPORT/AOWSEXPORT) operations
|   |-- Execute custom business logic (subprograms)
|       --> SOAP subprogram call (only available via SOAP)
|-- What's the deployment model?
|   |-- On-premise --> Basic auth or certificate auth
|   |-- Sage X3 Online (cloud) --> OAuth 2.0 (mandatory)
|-- What's the data volume?
|   |-- < WSSIZELIMIT per period --> Normal speed
|   |-- > WSSIZELIMIT --> Speed throttled by WSGRACESLOWDOWN factor
|   |-- > WSSIZELIMIT + WSGRACELIMIT --> Maximum throttling until period resets
|-- Pool sizing?
    |-- Low volume (< 100 calls/hour) --> Init: 1, Max: 2
    |-- Medium volume (100-1000 calls/hour) --> Init: 2, Max: 4-6
    |-- High volume (> 1000 calls/hour) --> Init: 4, Max: 8 (avoid > 8 init)
    |-- Schedule periodic pool restarts (daily/weekly) for stability

Quick Reference

OperationSOAP ActionKey ParametersResponse FieldsNotes
Read recordreadpublicName, objectKeysresultXml, status, messagesReturns single record by primary key
Create recordsavepublicName, objectXmlresultXml, status, messagesCreates new record; returns created object
Modify recordmodifypublicName, objectKeys, objectXmlresultXml, status, messagesUpdates existing record by key
Delete recorddeletepublicName, objectKeysstatus, messagesDeletes record by primary key
Query recordsquerypublicName, objectKeys, listSizeresultXml (list), statusReturns filtered list; set listSize for pagination
Export datarun (AOWSEXPORT)I_MODEXP, I_TCRITERE, I_EXECO_FILE, statusFile-based export with record separator
Import datarun (AOWSIMPORT)I_MODIMP, I_FILE, I_EXECstatus, messagesFile-based import; validate template first
Run subprogramrunpublicName, input parametersOutput parameters, statusExecutes custom X3 subprogram
Get WSDLGETN/AWSDL XML/soap-wsdl/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC?wsdl

Step-by-Step Integration Guide

1. Configure the SOAP pool in Syracuse administration

Navigate to Administration > Administration > Web Services > Classic SOAP pools configuration. Create a pool with alias, endpoint, locale, user, password, initialization size, and maximum size. Always enable "Auto start". [src3, src8]

Pool Configuration:
  Alias:             MYPOOL
  Endpoint:          MAIN (your X3 endpoint name)
  Locale:            English (United States)
  User:              WSUSER (dedicated web service user)
  Maximum Size:      4
  Initialization Size: 2
  Auto Start:        checked

Verify: Navigate to the pool list and confirm status shows green (active).

2. Set up the web service user in X3

Create a dedicated user for web services in Setup > Users > Users. The user must have web services connection authorization, standard authentication type, and password set to never expire. [src5]

User Setup:
  Login:              WSUSER
  Authentication:     Standard
  Password Expires:   Never
  Web Services Auth:  Enabled

Verify: Attempt to log in as the WSUSER via the X3 web interface to confirm the account is active.

3. Publish the target object as a web service

Navigate to Administration > Web Services > Classic SOAP Web services. Select the object to publish and click Publish. Re-validate all changed entities before republishing. [src5]

Verify: Use the built-in web service tester to invoke a read operation and confirm data returns.

4. Consume the WSDL and make a SOAP call

Retrieve the WSDL from the Syracuse server using the PU9+ endpoint URL. Add HTTP Basic Authentication headers to all requests. [src1, src4]

# Input:  Syracuse server URL, pool alias, X3 credentials
# Output: Query results from a published web service object

import requests
from requests.auth import HTTPBasicAuth

SYRACUSE_URL = "https://your-x3-server:8124"
POOL_ALIAS = "MYPOOL"

soap_body = """<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:wss="http://www.adonix.com/WSS">
  <soapenv:Body>
    <wss:query>
      <callContext>
        <codeLang>ENG</codeLang>
        <poolAlias>MYPOOL</poolAlias>
        <requestConfig>adxwss.optreturn=JSON</requestConfig>
      </callContext>
      <publicName>SOH</publicName>
      <objectKeys><key/></objectKeys>
      <listSize>10</listSize>
    </wss:query>
  </soapenv:Body>
</soapenv:Envelope>"""

response = requests.post(
    f"{SYRACUSE_URL}/soap-generic/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC",
    data=soap_body,
    headers={"Content-Type": "text/xml; charset=utf-8"},
    auth=HTTPBasicAuth("WSUSER", "password"),
    verify=True
)
print(f"Status: {response.status_code}")
print(response.text)

Verify: Response contains <status>1</status> (success) and resultXml with queried records.

Code Examples

Python: Read a Sales Order by Key

# Input:  Syracuse URL, pool alias, credentials, sales order number
# Output: Sales order details in JSON format

import requests
from requests.auth import HTTPBasicAuth
import xml.etree.ElementTree as ET

SYRACUSE_URL = "https://your-x3-server:8124"
POOL_ALIAS = "MYPOOL"
ORDER_NUMBER = "SO000123"

soap_body = f"""<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:wss="http://www.adonix.com/WSS">
  <soapenv:Body>
    <wss:read>
      <callContext>
        <codeLang>ENG</codeLang>
        <poolAlias>{POOL_ALIAS}</poolAlias>
        <requestConfig>adxwss.optreturn=JSON</requestConfig>
      </callContext>
      <publicName>SOH</publicName>
      <objectKeys>
        <key>{ORDER_NUMBER}</key>
      </objectKeys>
    </wss:read>
  </soapenv:Body>
</soapenv:Envelope>"""

resp = requests.post(
    f"{SYRACUSE_URL}/soap-generic/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC",
    data=soap_body,
    headers={"Content-Type": "text/xml; charset=utf-8"},
    auth=HTTPBasicAuth("WSUSER", "password"),
    verify=True
)

root = ET.fromstring(resp.text)
ns = {"wss": "http://www.adonix.com/WSS"}
status = root.find(".//status", ns)
if status is not None and status.text == "1":
    result_xml = root.find(".//resultXml", ns)
    print("Success:", result_xml.text)
else:
    messages = root.findall(".//message", ns)
    for msg in messages:
        print("Error:", msg.text)

C#/.NET: Consume SOAP Web Service with Basic Auth

// Input:  Syracuse URL, pool alias, web service user credentials
// Output: Query results via CAdxWebServiceXmlCC

// Custom class to inject Basic Auth headers (required for PU9+)
public class X3WebService : CAdxWebServiceXmlCCService
{
    public string Username { get; set; }
    public string Password { get; set; }

    protected override System.Net.WebRequest GetWebRequest(Uri uri)
    {
        var request = base.GetWebRequest(uri);
        string credentials = Convert.ToBase64String(
            System.Text.Encoding.ASCII.GetBytes($"{Username}:{Password}"));
        request.Headers["Authorization"] = $"Basic {credentials}";
        return request;
    }
}

var service = new X3WebService
{
    Url = "https://x3server:8124/soap-generic/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC",
    Username = "WSUSER",
    Password = "password"
};

var context = new CAdxCallContext { codeLang = "ENG", poolAlias = "MYPOOL" };
var result = service.query(context, "SOH", new CAdxParamKeyValue[0], 10);
if (result.status == 1) Console.WriteLine(result.resultXml);

cURL: Quick SOAP query test

# Input:  Syracuse URL, pool alias, credentials
# Output: SOAP response with queried records

curl -X POST \
  "https://x3server:8124/soap-generic/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC" \
  -u "WSUSER:password" \
  -H "Content-Type: text/xml; charset=utf-8" \
  -d '<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:wss="http://www.adonix.com/WSS">
  <soapenv:Body>
    <wss:query>
      <callContext>
        <codeLang>ENG</codeLang>
        <poolAlias>MYPOOL</poolAlias>
        <requestConfig>adxwss.optreturn=JSON</requestConfig>
      </callContext>
      <publicName>SOH</publicName>
      <objectKeys><key/></objectKeys>
      <listSize>5</listSize>
    </wss:query>
  </soapenv:Body>
</soapenv:Envelope>'

Data Mapping

SOAP Response Format Reference

Response FormatConfigurationContent StructureBest For
XML (default)adxwss.optreturn=XML<RESULT><LIN><FLD NAME="x" TYPE="y">value</FLD></LIN></RESULT>Typed data with metadata attributes
JSONadxwss.optreturn=JSON[{"field1": "value1", "field2": "value2"}]Lighter payloads, simpler parsing
Beautifiedadxwss.beautify=trueSame structure with CRLF formattingHuman-readable debugging

CAdxCallContext Field Reference

FieldRequiredTypeDescriptionGotcha
codeLangNoStringLanguage code (ENG, FRA, etc.)Uses pool default if omitted; affects field labels
poolAliasYesStringPool identifier from Syracuse adminMust match exactly; case-sensitive
poolIdNoStringForce specific client in poolIf specified client is busy, request waits
requestConfigNoString&-separated config params (adxwss.*)Use &amp; in XML for & separator

Data Type Gotchas

Error Handling & Failure Points

Common Error Codes

Code/StatusMeaningCauseResolution
HTTP 200, status=0Business errorX3 business rule violationCheck messages array for specific X3 error text; fix data and retry
HTTP 200, status=1SuccessOperation completedCheck resultXml for returned data
HTTP 401Authentication failedWrong credentials or user not authorizedVerify credentials; ensure user has web services authorization
HTTP 500Server errorPool not started or no web service child processesCheck pool status; verify child processes >= 1
HTTP 500 "No Web services accepted"Missing child processesWeb services children = 0 on hostSet to >= 1 in Administration > Servers > Hosts
TimeoutRequest timeoutPool clients busy or init size > 8Increase max size; reduce init size to <= 8

Failure Points in Production

Anti-Patterns

Wrong: Using the old WSDL endpoint URL after PU9 upgrade

# BAD - old endpoint still returns a WSDL but calls fail at runtime
wsdl_url = "http://x3server:8124/adxwsvc/services/CAdxWebServiceXmlCC?wsdl"

Correct: Use the PU9+ Syracuse WSDL endpoint

# GOOD - correct endpoint for PU9 and later
wsdl_url = "http://x3server:8124/soap-wsdl/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC?wsdl"

Wrong: Embedding credentials in the SOAP context body (pre-PU9 style)

<!-- BAD - PU9+ ignores credentials in SOAP body -->
<callContext>
  <codeLang>ENG</codeLang>
  <poolAlias>MYPOOL</poolAlias>
  <codeUser>ADMIN</codeUser>
  <password>secret</password>
</callContext>

Correct: Use HTTP Basic Authentication headers

# GOOD - PU9+ requires HTTP Basic Auth
import requests
from requests.auth import HTTPBasicAuth

response = requests.post(
    soap_url, data=soap_envelope,
    headers={"Content-Type": "text/xml; charset=utf-8"},
    auth=HTTPBasicAuth("WSUSER", "password")
)

Wrong: Never restarting the pool

# BAD - pools accumulate state corruption over time
# Set up pool once, never restart, wonder why calls fail after weeks

Correct: Schedule periodic pool restarts

# GOOD - automated daily pool restart via Syracuse REST API
curl -X POST -u "admin:password" \
  "http://x3server:8124/api1/syracuse/collaboration/syracuse/soapClassicPools('POOL_UUID')/$service/stop"
sleep 10
curl -X POST -u "admin:password" \
  "http://x3server:8124/api1/syracuse/collaboration/syracuse/soapClassicPools('POOL_UUID')/$service/start"

Common Pitfalls

Diagnostic Commands

# Get WSDL to verify endpoint is accessible
curl -u "WSUSER:password" \
  "https://x3server:8124/soap-wsdl/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC?wsdl" \
  -o wsdl.xml

# Check pool status via Syracuse REST API
curl -u "admin:password" \
  "http://x3server:8124/sdata/syracuse/collaboration/syracuse/soapClassicPools?representation=soapClassicPool.\$query" \
  -H "Accept: application/json" | python -m json.tool

# Stop a pool (use pool UUID from status query)
curl -X POST -u "admin:password" \
  "http://x3server:8124/api1/syracuse/collaboration/syracuse/soapClassicPools('POOL_UUID')/\$service/stop"

# Start a pool
curl -X POST -u "admin:password" \
  "http://x3server:8124/api1/syracuse/collaboration/syracuse/soapClassicPools('POOL_UUID')/\$service/start"

# Quick SOAP read test to verify auth and pool connectivity
curl -X POST -u "WSUSER:password" \
  "https://x3server:8124/soap-generic/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC" \
  -H "Content-Type: text/xml; charset=utf-8" \
  -d '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wss="http://www.adonix.com/WSS"><soapenv:Body><wss:query><callContext><codeLang>ENG</codeLang><poolAlias>MYPOOL</poolAlias><requestConfig>adxwss.optreturn=JSON</requestConfig></callContext><publicName>SOH</publicName><objectKeys><key/></objectKeys><listSize>1</listSize></wss:query></soapenv:Body></soapenv:Envelope>'

Version History & Compatibility

VersionReleaseStatusBreaking ChangesMigration Notes
V12 PU13+2025+CurrentNone from PU9Latest patches; SOAP remains stable
V12 PU92022SupportedWSDL URL changed; auth moved to HTTP headers; pool size no longer license-controlledUpdate WSDL URLs, add HTTP Basic Auth, reconfigure pools in Syracuse admin
V11 PU82020LegacyN/A (pre-PU9 baseline)Uses old /adxwsvc/ endpoint; credentials in SOAP context
V6-V72012-2016EOLN/AOriginal SOAP implementation; Console-based configuration

Deprecation Policy

Sage does not publish a formal API deprecation timeline for X3 SOAP web services. The progressive migration of modules to service-oriented architecture indicates SOAP is in long-term maintenance mode. No sunset date announced, but new investment is directed toward REST/SData 2.0. [src2]

When to Use / When Not to Use

Use WhenDon't Use WhenUse Instead
Write operations on classic X3 modules not yet migrated to service-oriented architectureRead-only data access where REST/SData 2.0 is availableSage X3 REST/SData 2.0 Web API
Batch import/export using X3 templates (AOWSIMPORT/AOWSEXPORT)Real-time high-frequency integrations (>100 calls/min)Middleware with queue-based architecture
Executing custom X3 subprograms for business logicIntegrating with Sage Intacct (different product)Sage Intacct REST API
On-premise deployments requiring certificate-based authGreenfield projects when REST/SData 2.0 covers your modulesREST/SData 2.0 (simpler, JSON-native)

Important Caveats

Related Units