The closed-source, multi-tenant SaaS suite covering nine pillars of supply chain and manufacturing. Every pillar shares one REST surface at /fscmRestApi/resources/11.13.18.05/. Expensive, complex, and the system of record for enterprises that have committed to Oracle. This page covers the integration surface, not the Fusion UI.
Oracle Fusion Cloud SCM is Oracle's cloud-native supply chain and manufacturing suite. It replaced E-Business Suite (EBS) for new deployments and is the canonical choice for enterprises standardised on Oracle Cloud Applications. There is no drop-in open-source equivalent for the full suite — if a customer is on Oracle, the REST APIs documented here are the integration surface.
Base URL pattern:
https://<pod>.fa.<region>.oraclecloud.com/fscmRestApi/resources/11.13.18.05/<resource> # <pod> — customer-specific, e.g. eabc-dev1, eabc-prod # <region> — Oracle Cloud region, e.g. em2 (Frankfurt), ap1 (Sydney) # SA customers: hosted em2 or ap1 — no Johannesburg Fusion Apps region # The /11.13.18.05/ segment is the resource version, not the app version
Every resource supports GET (list + single), POST (create), PATCH (partial update), DELETE, and in many cases BATCH. The nine pillars share this surface — planning, inventory, manufacturing, maintenance, order management, logistics, PLM, procurement, and analytics.
The canonical pattern: read from Fusion, run AI-assisted workflows (demand planning, reorder suggestions, quality alerts), write approved decisions back. Never replicate Fusion's data model — index against it. Cache on your side, refresh via Business Events or scheduled polls.
Two mechanisms. Basic auth with a dedicated integration user is simplest for server-to-server in a private network. OAuth2 via IDCS is required for anything public-facing or multi-tenant.
# Basic auth — integration user with Integration Specialist role # plus module-specific duty roles (Item Inquiry, PO Entry, etc.) import os, requests from requests.auth import HTTPBasicAuth POD = "https://eabc-dev1.fa.em2.oraclecloud.com" BASE = f"{POD}/fscmRestApi/resources/11.13.18.05" resp = requests.get( f"{BASE}/items", params={"limit": 25, "fields": "ItemId,ItemNumber,Description,ItemStatusValue"}, auth=HTTPBasicAuth(os.environ["FA_USER"], os.environ["FA_PASS"]), headers={"REST-Framework-Version": "4"}, timeout=30, ) resp.raise_for_status() for it in resp.json()["items"]: print(it["ItemNumber"], "-", it["Description"])
# OAuth2 — client credentials grant via IDCS / OCI IAM IDCS_URL = "https://idcs-xxxx.identity.oraclecloud.com" CLIENT_ID = os.environ["IDCS_CLIENT_ID"] CLIENT_SECRET = os.environ["IDCS_CLIENT_SECRET"] token_resp = requests.post( f"{IDCS_URL}/oauth2/v1/token", data={ "grant_type": "client_credentials", "scope": f"{POD}/urn:opc:resource:fa:instanceid=xxxx", }, auth=HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET), ) access_token = token_resp.json()["access_token"] # Tokens valid ~1 hour. Cache and refresh before expiry. # Use the token resp = requests.get( f"{BASE}/items", params={"limit": 25, "fields": "ItemId,ItemNumber"}, headers={"Authorization": f"Bearer {access_token}", "REST-Framework-Version": "4"}, )
Always proxy through your backend. Never use a privileged user like fa_admin for integrations. Never commit credentials to Git — use OCI Vault, AWS Secrets Manager, or equivalent. Rotate passwords quarterly.
Fusion's REST surface is consistent across all nine pillars. Learn these patterns once and they apply everywhere. The gotchas are in the defaults — verbose responses, unpinned framework versions, and absent pagination.
| Param | Purpose | Example |
|---|---|---|
limit | Page size (max 500) | limit=100 |
offset | Pagination offset | offset=200 |
fields | Restrict response fields | fields=ItemId,ItemNumber |
onlyData | Strip links arrays | onlyData=true |
expand | Inline child collections | expand=ItemRevision |
q | Filter expression (SQL-like) | q=ItemStatusValue='Active' |
finder | Named query | finder=findByItemNumber;ItemNumber=X |
orderBy | Sort | orderBy=CreationDate:desc |
Pagination loop. Always set limit and loop on hasMore. Never request totalResults=true unless you need the count — it forces a second aggregate query.
def fetch_all(base, path, params=None, auth=None): params = dict(params or {}) params.setdefault("limit", 500) offset = 0 while True: params["offset"] = offset r = requests.get( f"{base}/{path}", params=params, auth=auth, headers={"REST-Framework-Version": "4"}, timeout=60, ) r.raise_for_status() body = r.json() yield from body["items"] if not body.get("hasMore"): break offset += params["limit"] # Usage for item in fetch_all(BASE, "items", {"fields": "ItemNumber,Description", "q": "ItemStatusValue='Active'"}, auth=AUTH): process(item)
ETags for optimistic concurrency. Capture the ETag from GET, pass it as If-Match on PATCH. A 412 Precondition Failed means someone else edited the record — re-GET, re-apply, re-PATCH.
# GET with ETag captured r = requests.get(url, auth=auth, headers={"REST-Framework-Version": "4"}) etag = r.headers["ETag"] # PATCH with If-Match resp = requests.patch( url, json=changes, auth=auth, headers={"REST-Framework-Version": "4", "If-Match": etag, "Content-Type": "application/json"}, ) if resp.status_code == 412: # re-GET and retry with fresh ETag ...
Creating a sales order. POST to salesOrdersForOrderHub with source system keys for idempotency. Fusion deduplicates on (SourceTransactionSystem, SourceTransactionNumber).
order = {
"SourceTransactionNumber": "ECOM-2026-000042",
"SourceTransactionSystem": "SHOPIFY_ZA",
"TransactionalCurrencyCode": "ZAR",
"BusinessUnitName": "Acme ZA Business Unit",
"BuyingPartyNumber": "CUST-00042",
"RequestedShipDate": "2026-04-20T08:00:00+02:00",
"lines": [{
"SourceTransactionLineId": "1",
"ProductNumber": "WIDGET-ZA-001",
"OrderedQuantity": 2,
"OrderedUOMCode": "Ea",
"UnitSellingPrice": 299.00
}]
}
resp = requests.post(
f"{BASE}/salesOrdersForOrderHub",
json=order, auth=AUTH,
headers={"REST-Framework-Version": "4",
"Content-Type": "application/json"},
)
# Capture X-ORACLE-DMS-ECID from response for SR troubleshooting
ecid = resp.headers.get("X-ORACLE-DMS-ECID")
Every pillar exposes resources under the same /fscmRestApi/ base. This is the map. The resources listed are the ones you will actually use — not the full catalog, which runs to hundreds.
| Pillar | Key resources | Typical integration |
|---|---|---|
| Supply Chain Planning | planningCycles, demandForecasts, salesAndOperationsPlans |
Feed POS/e-com demand signals; read replenishment plans |
| Inventory Management | items, itemsV2, inventoryOnhandBalances, inventoryStagedTransactions |
Master data sync, stock visibility, receipt/issue posting |
| Manufacturing | workOrders, workDefinitions, standardOperations |
MES dispatch, shop floor IoT, WIP tracking |
| Maintenance | maintenanceWorkOrders, assets, maintenancePrograms |
Asset telemetry to preventive maintenance triggers |
| Order Management | salesOrdersForOrderHub, salesOrdersForCreation, holds |
E-com/retail order capture, hold release automation |
| Logistics (OTM/OWMS/GTM) | trips, shipments, receivingReceiptRequests, tradeTransactions |
Carrier booking, 3PL sync, customs declarations |
| Product Lifecycle (PLM) | itemsV2 (PLM fields), changeOrders, newItemRequests |
PIM sync, engineering change orchestration |
| Procurement | purchaseOrders, suppliers, requisitions, negotiations |
Supplier onboarding, PO automation, 3-way matching |
| Analytics (FDI) | Prebuilt subject areas on ADW; OTBI; BI Publisher | Downstream BI, nightly extracts to data lake |
Fusion has no SA-specific localisation (unlike Brazil with NFe/SPED). Getting it right is a configuration and integration-extension exercise. These are the things that matter.
Standard precision: 2 decimal places. Extended precision: 4dp for internal unit prices. Always round to 2dp on external-facing fields — Fusion rejects 4dp on some price attributes.
Tax regime ZA_VAT, standard rate 15%. SA retail integrations run VAT-inclusive pricing with reverse-calculation. B2B runs VAT-exclusive with tax added at invoice. Confirm which mode your tenant uses before building anything that touches prices.
Imports require SAD 500 filed with SARS Customs. GTM generates trade transaction data; EDI provider (EasyClear, CIS, Core Freight) converts to SARS format. HS 2022 tariff codes on the item master, updated annually from ITAC.
Stored on the BusinessClassifications child collection of the Supplier resource. Levels 1-8, EME, QSE, Black-Owned, Black Women-Owned. Certificates expire annually — build monitoring for 30/14/7 day warnings.
Fusion holds PII (names, addresses, ID numbers). Document it in your processing register. Cross-border transfer (pods in Frankfurt or Sydney) needs a DPA with Oracle. Implement anonymisation for deletion requests — PATCH PII to pseudonyms, keep transaction history for SARS (5-year retention).
SA grid is unreliable. Never call Fusion directly from request handlers. Use the outbox pattern: write intent locally, worker drains to Fusion with retries. Circuit breakers on all Fusion calls. Persistent retry queues (Redis Streams, Postgres, SQS).
B-BBEE supplier query. Pull suppliers with their classification data for procurement scorecard reporting.
# Query suppliers with B-BBEE classifications resp = requests.get( f"{BASE}/suppliers", params={ "fields": "Supplier,TaxpayerId,SupplierTypeCode", "expand": "BusinessClassifications", "q": "TaxpayerCountry='ZA'", "onlyData": "true", "limit": 500, }, auth=AUTH, headers={"REST-Framework-Version": "4"}, ) for s in resp.json()["items"]: classifications = [c["Classification"] for c in s.get("BusinessClassifications", [])] print(s["Supplier"], "|", ", ".join(classifications))
Six specific ways Oracle Fusion will burn you if you skip the fine print. Every one of these has cost someone a production incident.
If you omit this header, Fusion defaults to v1 — verbose, inconsistent, and liable to change shape when Oracle ships a quarterly update. Pin to 4. Review release readiness notes before bumping. Your integration will silently break otherwise.
Default page size is small and undocumented. Always set limit (max 500) and loop on hasMore. Never request totalResults=true unless you need the count — it forces an expensive second query on every call.
PATCH without If-Match can silently clobber concurrent edits. Always capture ETags from GET and pass them on write. Handle 412 Precondition Failed with re-read and retry.
Default responses include 50+ attributes per record. Always use fields= to restrict. Add onlyData=true to strip the links arrays that bloat every response. Payload drops 5-20x.
Oracle does not publish universal limits, but sustained >20 rps from a single user triggers 429s. Bursts of 100+ rps get 503d. Build exponential backoff with jitter. Prefer BATCH for bulk work — it counts as one request.
Items, supplier sites, and customer accounts are date-effective. Forgetting the Effective-Of: RangeMode=CURRENT header returns all versions including expired ones. Confusing duplicates that look like bugs but are just history.
| Use Oracle Fusion SCM when | Skip it when |
|---|---|
| The customer has standardised on Oracle Cloud Applications | The customer is on EBS or JD Edwards (different products, different APIs) |
| You need a full suite — planning, manufacturing, procurement, logistics, PLM — under one roof | You only need inventory + orders and the budget is tight (ERPNext or a lightweight stack is cheaper) |
| Multi-site, multi-currency, complex supply chains across geographies | Single-site, single-currency, simple product catalog (Oracle is wildly overspec) |
| Regulatory requirements demand an enterprise-grade audit trail | You need fast iteration and full control over the codebase (Fusion is closed-source SaaS) |
| Fusion Data Intelligence provides out-of-the-box analytics you would otherwise build from scratch | You already have a mature data warehouse and BI stack — FDI adds cost without enough incremental value |
Oracle Fusion is expensive, complex, and slow to configure. Implementation timelines measured in months, not weeks. Licensing is opaque. But for organisations that have committed to Oracle, the REST surface is solid, the data model is well-thought-out, and the nine-pillar coverage means fewer point-to-point integrations. The cost is real; the coverage is also real.
Oracle Fusion is the heavyweight in the ERP sub-domain. It connects to infrastructure for the proxy layer, to open-source alternatives for customers who cannot justify the licensing, and to analytics for the data that lives downstream.
improves biz/erp — its enterprise-grade patterns (ETags, BATCH, date-effective resources) raise the bar for the shared ERP skill.Oracle's docs are extensive. The canonical SKILL.md in the 2nth-ai/skills repo is the integration-focused distillation. Always check the current release (26B) — Fusion ships quarterly and fields do change.