Sage X3 ERP AI integration expert.
Sage X3 (formerly Sage Enterprise Management) is a mid-market ERP. Modern instances expose a GraphQL API via the Syracuse web server using Yoga GraphQL.
Endpoint pattern: https://
HTTP Basic Authentication over HTTPS.
Authorization: Basic base64(USERNAME:PASSWORD)
Never hardcode credentials. Use environment variables, wrangler secret put, or .env files.
x3MasterData — Master data
├── customer — Customer business partners
├── supplier — Supplier business partners
├── product — Product catalog
└── stockSite — Warehouses / stock sites
x3Sales — Sales domain
├── salesOrder — Sales orders
├── salesInvoice — Sales invoices
└── salesDelivery — Delivery notes
x3Purchasing — Purchasing domain
├── purchaseOrder — Purchase orders
└── purchaseReceipt — Goods receipt
x3Stock — Inventory domain
├── stockChange — Stock movements
└── stockCount — Stock counts
x3Accounting — Financial domain
├── journalEntry — Journal entries
└── generalLedger — GL accounts
Important: Schema varies by installation. Always introspect first.
All queries use Relay cursor-based pagination with edges/node:
query {
x3MasterData {
customer {
query(first: 10, after: "cursor_value") {
edges {
node {
code {
code
companyName1
country { code countryName }
currency { code localizedDescription }
isCustomer
isSupplier
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
Key rule: All fields live inside node.code, not directly on node.
OData-style filter strings:
query(first: 50, filter: "country.code eq 'ZA' and isCustomer eq true")
query(first: 100, filter: "orderDate ge '2026-01-01'")
| Operator | Meaning | Example |
|---|---|---|
eq | Equals | status eq 'Active' |
ne | Not equals | country.code ne 'ZA' |
gt/ge/lt/le | Comparison | totalAmount gt 10000 |
contains() | Substring | contains(companyName1, 'Umbrella') |
and/or | Logical | isCustomer eq true and isSupplier eq true |
Always introspect to discover what's available:
{
__schema {
queryType {
fields {
name
description
type { name kind ofType { name kind } }
}
}
}
}
Discover fields on a specific type:
{
__type(name: "X3MasterDataQuery") {
fields {
name
type { name kind }
}
}
}
code: Data is at node.code.fieldName, not node.fieldNamefirst — omitting returns 0 results'2026-01-01'NODE_TLS_REJECT_UNAUTHORIZED=0