biz/erp/sage-x3

SAGE X3

Sage X3 ERP AI integration expert.

production Any HTTP client, GraphQL client, or Cloudflare Workers
improves: biz/erp

Sage X3 AI Integration

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://://api

Authentication

HTTP Basic Authentication over HTTPS.

Authorization: Basic base64(USERNAME:PASSWORD)

Never hardcode credentials. Use environment variables, wrangler secret put, or .env files.

Schema Structure

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.

Query Pattern

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.

Filtering

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'")
OperatorMeaningExample
eqEqualsstatus eq 'Active'
neNot equalscountry.code ne 'ZA'
gt/ge/lt/leComparisontotalAmount gt 10000
contains()Substringcontains(companyName1, 'Umbrella')
and/orLogicalisCustomer eq true and isSupplier eq true

Introspection

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 }
    }
  }
}

Common Gotchas

See Also