/adxwsvc/services/CAdxWebServiceXmlCC?wsdl to /soap-wsdl/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC?wsdl. The old WSDL still validates but calls silently fail at runtime. [src4]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]
| Property | Value |
|---|---|
| Vendor | Sage |
| System | Sage X3 (Enterprise Management) V12 |
| API Surface | SOAP (RPC/encoded), via CAdxWebServiceXmlCC |
| Current API Version | V12 (PU9+) |
| Editions Covered | Standard, Premium (all editions) |
| Deployment | Hybrid (on-premise and Sage X3 Online/cloud) |
| API Docs | Sage X3 SOAP Web Services |
| Status | GA (maintenance - Sage migrating to REST/SData 2.0) |
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 Surface | Protocol | Best For | Operations | Rate Limit | Real-time? | Bulk? |
|---|---|---|---|---|---|---|
| SOAP (CAdxWebServiceXmlCC) | HTTPS/XML (RPC/encoded) | Write operations on classic objects, subprogram execution | CRUD, query, import, export, subprogram | License-based (WSSIZELIMIT MB/period) | Yes | Via import/export |
| REST Web API (SData 2.0) | HTTPS/JSON | Read operations on all modules, write on service-oriented modules | GET, POST, PUT, DELETE | License-based | Yes | No native bulk |
| SOAP Import/Export | HTTPS/XML | File-based batch data exchange | AOWSIMPORT, AOWSEXPORT | Shared with SOAP limit | No (batch) | Yes |
| Limit Type | Value | Applies To | Notes |
|---|---|---|---|
| Max records per query (listSize) | Configurable per call | SOAP query operations | Set via listSize parameter; no hard system maximum documented |
| Max pool clients per node.js process | Configured via Maximum Size | SOAP pool | Typical range: 2-10 clients per pool |
| Unused client timeout | 20 min (default) | Individual pool client | Idle clients are automatically stopped after this period |
| Client life timeout | 720 min / 12 hours (default) | Individual pool client | Channels reset after this duration regardless of activity |
| Limit Type | Value | Window | Edition 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 WSSIZELIMIT | Same as WSPERIOD | Calls continue but speed degrades |
| Throttle factor (WSGRACESLOWDOWN) | Speed divided by configured factor (e.g., 5x) | Until period resets | When daily limit reached, speed divided by 5 until end of day |
| Limit Type | Value | Notes |
|---|---|---|
| Pool initialization size | Configurable (e.g., 2) | Clients created at pool startup per node.js process |
| Pool maximum size | Configurable (e.g., 4-10) | Maximum concurrent clients per node.js process |
| Web service child processes | >= 1 required on host | Set via Administration > Servers > Hosts; 0 = HTTP 500 errors |
| Initialization size limit | Avoid > 8 | Setting initialization size above 8 may cause timeout errors during pool start/stop |
Sage X3 SOAP web services support three authentication mechanisms, with availability depending on deployment model. [src2]
| Flow | Use When | Deployment | Credential Storage | Notes |
|---|---|---|---|---|
| Basic Authentication (HTTP) | On-premise integrations, simplest setup | On-premise only | Username/password in HTTP Authorization header | PU9+ moved auth from SOAP context to HTTP headers. Password must be set to never expire. [src4, src5] |
| Certificate Authentication | On-premise production environments | On-premise only | X.509 certificate | SSL client certificate presented with each request |
| OAuth 2.0 | Sage X3 Online (cloud) - mandatory | Cloud only | Bearer token in Authorization header | Only method available in Sage X3 Online; configure via Sage ID [src2] |
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
| Operation | SOAP Action | Key Parameters | Response Fields | Notes |
|---|---|---|---|---|
| Read record | read | publicName, objectKeys | resultXml, status, messages | Returns single record by primary key |
| Create record | save | publicName, objectXml | resultXml, status, messages | Creates new record; returns created object |
| Modify record | modify | publicName, objectKeys, objectXml | resultXml, status, messages | Updates existing record by key |
| Delete record | delete | publicName, objectKeys | status, messages | Deletes record by primary key |
| Query records | query | publicName, objectKeys, listSize | resultXml (list), status | Returns filtered list; set listSize for pagination |
| Export data | run (AOWSEXPORT) | I_MODEXP, I_TCRITERE, I_EXEC | O_FILE, status | File-based export with record separator |
| Import data | run (AOWSIMPORT) | I_MODIMP, I_FILE, I_EXEC | status, messages | File-based import; validate template first |
| Run subprogram | run | publicName, input parameters | Output parameters, status | Executes custom X3 subprogram |
| Get WSDL | GET | N/A | WSDL XML | /soap-wsdl/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC?wsdl |
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).
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.
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.
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.
# 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)
// 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);
# 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>'
| Response Format | Configuration | Content Structure | Best For |
|---|---|---|---|
| XML (default) | adxwss.optreturn=XML | <RESULT><LIN><FLD NAME="x" TYPE="y">value</FLD></LIN></RESULT> | Typed data with metadata attributes |
| JSON | adxwss.optreturn=JSON | [{"field1": "value1", "field2": "value2"}] | Lighter payloads, simpler parsing |
| Beautified | adxwss.beautify=true | Same structure with CRLF formatting | Human-readable debugging |
| Field | Required | Type | Description | Gotcha |
|---|---|---|---|---|
| codeLang | No | String | Language code (ENG, FRA, etc.) | Uses pool default if omitted; affects field labels |
| poolAlias | Yes | String | Pool identifier from Syracuse admin | Must match exactly; case-sensitive |
| poolId | No | String | Force specific client in pool | If specified client is busy, request waits |
| requestConfig | No | String | &-separated config params (adxwss.*) | Use & in XML for & separator |
| Code/Status | Meaning | Cause | Resolution |
|---|---|---|---|
| HTTP 200, status=0 | Business error | X3 business rule violation | Check messages array for specific X3 error text; fix data and retry |
| HTTP 200, status=1 | Success | Operation completed | Check resultXml for returned data |
| HTTP 401 | Authentication failed | Wrong credentials or user not authorized | Verify credentials; ensure user has web services authorization |
| HTTP 500 | Server error | Pool not started or no web service child processes | Check pool status; verify child processes >= 1 |
| HTTP 500 "No Web services accepted" | Missing child processes | Web services children = 0 on host | Set to >= 1 in Administration > Servers > Hosts |
| Timeout | Request timeout | Pool clients busy or init size > 8 | Increase max size; reduce init size to <= 8 |
Schedule automated daily/weekly pool restarts via REST API stop/start endpoints. [src6]Update to /soap-wsdl/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC?wsdl [src4]Re-validate and republish after ANY object modification. [src5]Monitor data volume usage; log CAdxTechnicalInfos.totalDuration to detect slowdowns. [src1]Size pools for concurrent load; use poolId for critical operations. [src1]# BAD - old endpoint still returns a WSDL but calls fail at runtime
wsdl_url = "http://x3server:8124/adxwsvc/services/CAdxWebServiceXmlCC?wsdl"
# GOOD - correct endpoint for PU9 and later
wsdl_url = "http://x3server:8124/soap-wsdl/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC?wsdl"
<!-- BAD - PU9+ ignores credentials in SOAP body -->
<callContext>
<codeLang>ENG</codeLang>
<poolAlias>MYPOOL</poolAlias>
<codeUser>ADMIN</codeUser>
<password>secret</password>
</callContext>
# 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")
)
# BAD - pools accumulate state corruption over time
# Set up pool once, never restart, wonder why calls fail after weeks
# 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"
Start with init size 2, max 4. Scale up based on observed needs, never > 8 for init. [src3, src5]Log technicalInfos from every response. Alert when poolWaitDuration > 5s or totalDuration > 30s. [src1]Test from the actual integration client with production-like conditions. [src5]Include web service republication in your change management process. [src5]Check whether the target module has been migrated before choosing REST. [src2]Always parse the messages array for record-level errors even when status is 1. [src7]# 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 | Release | Status | Breaking Changes | Migration Notes |
|---|---|---|---|---|
| V12 PU13+ | 2025+ | Current | None from PU9 | Latest patches; SOAP remains stable |
| V12 PU9 | 2022 | Supported | WSDL URL changed; auth moved to HTTP headers; pool size no longer license-controlled | Update WSDL URLs, add HTTP Basic Auth, reconfigure pools in Syracuse admin |
| V11 PU8 | 2020 | Legacy | N/A (pre-PU9 baseline) | Uses old /adxwsvc/ endpoint; credentials in SOAP context |
| V6-V7 | 2012-2016 | EOL | N/A | Original SOAP implementation; Console-based configuration |
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]
| Use When | Don't Use When | Use Instead |
|---|---|---|
| Write operations on classic X3 modules not yet migrated to service-oriented architecture | Read-only data access where REST/SData 2.0 is available | Sage 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 logic | Integrating with Sage Intacct (different product) | Sage Intacct REST API |
| On-premise deployments requiring certificate-based auth | Greenfield projects when REST/SData 2.0 covers your modules | REST/SData 2.0 (simpler, JSON-native) |