How do you integrate Salesforce with Oracle ERP Cloud end-to-end?
TL;DR
Bottom line: Use Oracle Integration Cloud (OIC) with pre-built Salesforce and ERP Cloud adapters for the fastest path to production; use FBDI for bulk/batch imports (>100 records) and REST API for real-time individual record sync.
Key limit: Oracle ERP Cloud REST API caps POST operations at 500 records; for anything larger, FBDI (File-Based Data Import) via UCM upload + ESS job is mandatory.
Watch out for: FBDI CSV templates are entity-specific with strict column ordering -- a single misplaced column causes silent import failures; always generate templates from Oracle ERP Cloud's export function, not manually.
Best for: Lead-to-Cash automation where Salesforce owns the customer relationship and pipeline, Oracle ERP Cloud owns order management, fulfillment, AR invoicing, and financial close.
Authentication: Salesforce OAuth 2.0 JWT Bearer (server-to-server) + Oracle ERP Cloud OAuth 2.0 via IDCS (client credentials or JWT assertion); OIC manages both connections natively.
System Profile
This integration playbook covers the end-to-end data flow between Salesforce CRM and Oracle ERP Cloud (Fusion Applications) for the Lead-to-Cash (L2C) process. Salesforce serves as the system of record for leads, accounts, opportunities, and quotes. Oracle ERP Cloud serves as the system of record for customers, sales orders, fulfillment, AR invoices, receipts, and the general ledger. Oracle Integration Cloud (OIC) serves as the recommended middleware, providing pre-built adapters for both systems with native support for FBDI imports, business event subscriptions, and error handling.
This card does NOT cover: Salesforce CPQ-to-Oracle ERP Cloud pricing sync, Oracle ERP Cloud Procurement (P2P) flows, or Oracle ERP Cloud HCM integration.
System
Role
API Surface
Direction
Salesforce (API v62.0)
CRM -- source of truth for leads, accounts, opportunities, quotes
REST API, Composite API, Bulk API 2.0, Platform Events, CDC
Trigger on SF record changes, invoke SF operations
Adapter-managed
OIC message pack
Yes
No
OIC ERP Cloud Adapter
OIC
Native
FBDI import, business event subscription, callback
Adapter-managed
OIC message pack
Both
Yes
Rate Limits & Quotas
Per-Request Limits
Limit Type
Value
System
Notes
Max records per SOQL query page
2,000
Salesforce
Use queryMore/nextRecordsUrl for pagination
Max Composite subrequests
25
Salesforce
All-or-nothing by default
Max REST request body
50 MB
Salesforce
Max Bulk API file size
150 MB
Salesforce
Split larger files
Max records per REST POST
500
Oracle ERP Cloud
Use FBDI for larger volumes
Max FBDI file size (UCM upload)
250 MB
Oracle ERP Cloud
Split larger data sets into multiple files
Max OIC payload size
10 MB
OIC
Use stage file for larger payloads
Apex callout timeout
120 seconds
Salesforce
Per individual callout
Rolling / Daily Limits
Limit Type
Value
Window
Notes
Salesforce API calls
100,000 + 1,000 per user license
24h rolling
Enterprise edition base
Salesforce Bulk API batches
15,000
24h rolling
Shared across all editions
Oracle ERP Cloud concurrent ESS jobs
16-24 (pod-dependent)
Real-time
Shared across ALL scheduled processes
OIC messages
Per message pack (5K/20K/50K/100K per hour)
Hourly
Exceeded = throttled, not blocked
Salesforce Streaming events
100K-10M
24h
Depends on add-on licenses
Salesforce concurrent long-running requests
25
Per org, real-time
Requests >20s count as long-running
Transaction / Governor Limits
Limit Type
Per-Transaction Value
System
Notes
SOQL queries
100
Salesforce
Includes queries from triggers -- cascading triggers consume from same pool
DML statements
150
Salesforce
Each insert/update/delete counts as 1, regardless of record count
Callouts (HTTP)
100
Salesforce
External HTTP requests within a transaction
CPU time
10,000 ms (sync), 60,000 ms (async)
Salesforce
Exceeded = transaction abort
Heap size
6 MB (sync), 12 MB (async)
Salesforce
Total email invocations
10
Salesforce
Per Apex transaction
Authentication
System
Flow
Use When
Token Lifetime
Refresh?
Notes
Salesforce
OAuth 2.0 JWT Bearer
Server-to-server integration (recommended)
Session timeout (default 2h)
New JWT per request
Requires Connected App + digital certificate
Salesforce
OAuth 2.0 Web Server
User-context operations
Access: 2h, Refresh: until revoked
Yes
Requires callback URL
Salesforce
Client Credentials
First-party server-to-server
Access: 2h
No
Simpler than JWT, limited scope
Oracle ERP Cloud
OAuth 2.0 Client Credentials via IDCS
Server-to-server (recommended for OIC)
Access: 1h (configurable)
Yes
Register OAuth client in IDCS; scope to ERP Cloud
Oracle ERP Cloud
OAuth 2.0 JWT Assertion via IDCS
Automated integration without user context
Access: 1h
New JWT per request
Requires IDCS app registration + certificate
Oracle ERP Cloud
Basic Auth (username/password)
Legacy or quick testing only
Session-based
N/A
Do NOT use in production -- no token rotation, no MFA
OIC
Managed Connections
All OIC integrations
OIC-managed
OIC-managed
OIC stores and refreshes credentials for both SF and ERP
Authentication Gotchas
Oracle IDCS OAuth client setup requires Domain Administrator: The ERP Cloud Service Administrator alone cannot register the OAuth client. Plan for cross-team coordination and 1-2 week lead time. [src3]
Salesforce JWT flow requires per-environment certificates: Self-signed works for sandbox; CA-signed recommended for production. The Connected App must pre-authorize the integration user. [src1]
Oracle ERP Cloud session timeout is admin-configurable: Don't hardcode token lifetimes. Default is 60 minutes but admins can change it. Always implement token refresh logic. [src3]
OIC Salesforce Adapter uses SOAP API internally: Even though you configure REST-like operations, the adapter authenticates via SOAP login. Ensure the integration user has "API Enabled" permission AND SOAP API access. [src2]
OAuth refresh tokens expire after 90 days of non-use in Salesforce: Unattended integrations that go dormant silently fail. Implement a keep-alive token refresh cycle. [src1]
Constraints
Oracle ERP Cloud REST API is not designed for bulk operations: Max 500 records per POST. For anything over ~100 records, Oracle's own guidance is to use FBDI. REST is for real-time, individual record operations only.
FBDI CSV templates are entity-specific and column-order-dependent: A single misplaced or missing column causes the ESS import job to fail silently or with cryptic "Hierarchy Error" messages. Always download the template from Oracle ERP Cloud.
OIC message pack governs total throughput: Every adapter invocation (trigger + invoke) counts as messages. A single integration that syncs 10,000 orders/day with 5 lookups each consumes 60,000 messages.
Salesforce governor limits apply to the ENTIRE transaction: A trigger that fires on 200 records has ONE pool of 100 SOQL queries and 100 callouts for ALL 200 records combined. Bulkify all Apex code.
Oracle ERP Cloud ESS job concurrency is shared: The 16-24 concurrent job slots are shared across ALL scheduled processes -- not just integrations. Month-end GL close can consume all slots.
Bidirectional sync requires explicit conflict resolution: Without a defined "source of truth" per field, update loops between Salesforce and Oracle ERP Cloud will oscillate and consume API limits.
Oracle ERP Cloud FBDI customer import requires manual batch identifier: Unlike other entities, customer FBDI import needs a pre-created batch ID that cannot be auto-generated by OIC.
Integration Pattern Decision Tree
START -- Salesforce <-> Oracle ERP Cloud L2C Integration
|
+-- What entity are you syncing?
| +-- Accounts/Customers
| | +-- Direction: SF Account --> Oracle Customer
| | +-- Volume < 100/batch? --> Oracle REST API
| | +-- Volume > 100/batch? --> FBDI: Customer Interface CSV
| | +-- Real-time? --> OIC triggered by SF Platform Event or CDC
| | +-- ALWAYS sync customers BEFORE orders
| |
| +-- Opportunities/Orders
| | +-- Trigger: Opportunity Closed-Won in SF
| | +-- Volume < 100/batch? --> Oracle REST API
| | +-- Volume > 100/batch? --> FBDI: Order Import CSV
| | +-- Pre-check: Customer + Items exist in Oracle
| | +-- Store Oracle Order Number back in SF
| |
| +-- Invoices (sync-back)
| | +-- Trigger: AR Invoice created in Oracle
| | +-- Direction: Oracle --> SF via OIC + Business Events
| |
| +-- Payments/Receipts (sync-back)
| | +-- Trigger: Receipt applied in Oracle AR
| | +-- Direction: Oracle --> SF via OIC scheduled poll
| |
| +-- Products/Items
| +-- Direction: Oracle Item Master --> SF Product2
| +-- Sync: Scheduled batch (items change infrequently)
|
+-- Which integration pattern?
| +-- Real-time (<1s) --> OIC + SF Adapter trigger + Oracle REST API
| +-- Near-real-time (1-15 min) --> OIC scheduled poll or Platform Events
| +-- Batch/bulk --> OIC with FBDI pattern (CSV + UCM + ESS)
| +-- Event-driven --> SF Platform Events + Oracle Business Events via OIC
|
+-- Error tolerance?
+-- Zero-loss --> Idempotency + OIC error hospital + DLQ
+-- Best-effort --> OIC with retry + email notification
Quick Reference
Step
Source System
Action
Target System
Data Objects
Method
Failure Handling
1
Salesforce
Account created/updated
Oracle ERP Cloud
Receivables Customer
OIC: SF Adapter → REST API or FBDI
Retry 3x, then OIC error hospital
2
Salesforce
Opportunity Closed-Won
Oracle ERP Cloud
Sales Order + Lines
OIC: SF Adapter → FBDI or REST API
Validate customer exists; retry 3x, then DLQ
3
Oracle ERP Cloud
Order booked (Business Event)
Salesforce
Opportunity status update
OIC: ERP Adapter → SF REST API
Retry 3x, manual review
4
Oracle ERP Cloud
Shipment confirmed
Salesforce
Order fulfillment status
OIC: ERP Adapter → SF REST API
Retry 3x, log to pipeline
5
Oracle ERP Cloud
AR Invoice created
Salesforce
Custom Invoice object
OIC: ERP Adapter → SF REST API
Retry 3x, then DLQ
6
Oracle ERP Cloud
Receipt applied
Salesforce
Payment record update
OIC: Scheduled → SF REST API
Nightly reconciliation
7
Oracle ERP Cloud
Item master changed
Salesforce
Product2 / PricebookEntry
OIC: Scheduled poll → SF Bulk API
Log mismatches, manual review
Step-by-Step Integration Guide
1. Configure OIC Connections
Set up OIC connections for both Salesforce and Oracle ERP Cloud. The Salesforce Adapter requires a Connected App with OAuth 2.0 credentials. The Oracle ERP Cloud Adapter uses the native Fusion connection. [src2, src5]
Verify: Test both connections in OIC Console -- green checkmark indicates successful authentication.
2. Build Account-to-Customer Sync
Create an OIC integration that triggers on Salesforce Account changes and creates/updates Oracle ERP Cloud Receivables Customers. [src4, src5]
OIC Integration Flow:
Trigger: Salesforce Adapter (Platform Events or Scheduled Query)
--> Object: Account
--> Fields: Id, Name, BillingStreet, BillingCity, BillingState, BillingPostalCode, BillingCountry
Map: Salesforce Account --> Oracle Customer fields (see Data Mapping section)
Invoke: Oracle ERP Cloud Adapter
--> < 100 records: REST API POST /fscmRestApi/resources/latest/receivablesCustomers
--> > 100 records: FBDI pattern (CSV + UCM + ESS job)
Response: Log Oracle Customer Number, write back to SF Account custom field
Verify: Create a test Account in Salesforce sandbox -- confirm Customer appears in Oracle ERP Cloud Receivables.
3. Build Order Sync (Opportunity Closed-Won)
Trigger on Salesforce Opportunity stage change to "Closed Won" and create a Sales Order in Oracle ERP Cloud. [src4, src5]
OIC Integration Flow:
Trigger: Salesforce Adapter
--> Object: Opportunity (StageName = 'Closed Won')
--> Include: OpportunityLineItems
Pre-Validation:
--> Customer exists in Oracle? If no, create first
--> All items exist in Oracle? If no, fail with error
Invoke: Oracle ERP Cloud Adapter
--> REST API: POST /fscmRestApi/resources/latest/salesOrdersForOrderHub
--> Or FBDI: Order Import template
Post: Write Oracle Order Number back to SF Opportunity
Verify: Close an Opportunity in Salesforce sandbox -- confirm Sales Order in Oracle ERP Cloud Order Management.
4. Build Invoice Sync-Back
Subscribe to Oracle ERP Cloud Business Events for AR Invoice creation and push invoice data back to Salesforce. [src3, src5]
SF allows 255, Oracle allows 360 -- watch for special characters
Account.Id (18-char)
receivablesCustomers.OrigSystemReference
String
Direct (cross-reference key)
Oracle OrigSystemReference max 240 chars
Account.BillingStreet
CustomerAddress.Address1
String
Truncate to 240 chars
SF multi-line textarea; Oracle Address1 is single line
Account.BillingCountry
CustomerAddress.Country
String
Map SF country name to Oracle ISO code
SF stores "United States"; Oracle expects "US"
Account.CurrencyIsoCode
receivablesCustomers.CurrencyCode
String
Direct if multi-currency
Mismatch causes invoice posting failures
Opportunity.Amount
salesOrdersForOrderHub.OrderTotal
Currency
Convert currency if multi-currency org
Exchange rate must match Oracle GL daily rate
OpportunityLineItem.Quantity
OrderLine.OrderedQuantity
Decimal
Direct
SF allows 8 decimals; Oracle typically 2-6 depending on UOM
OpportunityLineItem.UnitPrice
OrderLine.UnitSellingPrice
Currency
Direct
Must match Oracle price list or pass override flag
OpportunityLineItem.Product2.ProductCode
OrderLine.ProductNumber
String
Lookup: SF ProductCode to Oracle Item Number
Must exist in Oracle Item Master
Opportunity.CloseDate
salesOrdersForOrderHub.RequestedShipDate
Date
Direct or business logic
Timezone mismatch can shift date by one day
Data Type Gotchas
Country codes: Salesforce stores full country names by default; Oracle expects ISO 3166 alpha-2 codes. Enable State/Country Picklists in Salesforce or maintain a mapping table in OIC. [src5]
Currency handling: If Salesforce org is multi-currency, CurrencyIsoCode may differ from Oracle ledger currency. Oracle rejects transactions where currency doesn't match the customer's profile. [src3]
Address line splitting: Salesforce BillingStreet is a single textarea. Oracle has Address1-Address4 (each 240 chars). Split on newlines or truncate. [src4]
Date/timezone mismatch: Oracle REST API uses ISO 8601; Salesforce dates are YYYY-MM-DD. Timezone differences between SF user timezone and Oracle server timezone can shift dates by one day. [src3]
Null handling: Salesforce returns null for empty fields. Oracle REST API ignores null on create but treats explicit null as "clear the value" on update. [src3]
Error Handling & Failure Points
Common Error Codes
Code/Error
System
Meaning
Cause
Resolution
429 Too Many Requests
Both
Rate limit exceeded
Too many API calls
Exponential backoff: wait 2^n seconds, max 5 retries
FBDI "Hierarchy Error"
Oracle ERP Cloud
FBDI validation failure
Missing/misplaced column or invalid parent reference
Re-download CSV template from Oracle; validate all columns
FBDI import succeeds but creates zero records: ESS job completes SUCCESS but interface table has row-level validation errors. Always check the ESS output log AND interface table error columns. Fix: query fscmRestApi/resources/latest/erpintegrations to retrieve import log from UCM. [src4, src6]
CDC event gaps between Salesforce and OIC: If OIC goes down, CDC events older than 3 days are purged. OIC does not replay automatically. Fix: implement a catch-up integration with time-windowed SOQL query on reconnection. [src2]
Currency mismatch between SF Opportunity and Oracle Order: Oracle validates against customer's allowed transaction currencies. Mismatch causes silent order creation failure. Fix: validate currency against Oracle setup before submitting order. [src3, src5]
Month-end ESS job contention: GL period close, revenue recognition jobs consume all ESS slots, blocking FBDI imports indefinitely. Fix: schedule integration FBDI jobs outside month-end windows (avoid days 1-3 of each month). [src3, src7]
Salesforce FLS blocks sync-back: Integration user profile lacks write access to custom Oracle cross-reference fields. Update silently succeeds but field remains empty. Fix: create dedicated integration user profile with explicit FLS grants. [src1]
OIC connection token expiry during long-running batch: Oracle OAuth token expires mid-integration for batches >1 hour. Fix: set connection idle timeout to match batch duration; add explicit token refresh step. [src2, src3]
Anti-Patterns
Wrong: Synchronous callouts from Salesforce triggers to Oracle ERP Cloud
// BAD -- Apex trigger makes synchronous HTTP callout to Oracle for every Account update
// This will hit governor limits (100 callouts per transaction) when bulk updates occur
trigger AccountSync on Account (after update) {
for (Account acc : Trigger.new) {
Http h = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint('https://erp.oraclecloud.com/fscmRestApi/...');
req.setMethod('POST');
h.send(req); // 200 accounts = 200 callouts = GOVERNOR LIMIT EXCEEDED
}
}
Correct: Publish Platform Events; let OIC subscribe and process asynchronously
// GOOD -- Trigger publishes Platform Event; OIC subscribes and processes in batches
trigger AccountSync on Account (after update) {
List<Account_Change__e> events = new List<Account_Change__e>();
for (Account acc : Trigger.new) {
events.add(new Account_Change__e(
Account_Id__c = acc.Id,
Change_Type__c = 'UPDATE'
));
}
EventBus.publish(events); // One DML, no callouts, no governor limit risk
}
// OIC Salesforce Adapter subscribes to Account_Change__e
Wrong: Polling Oracle ERP Cloud REST API every 60 seconds for status changes
# BAD -- Polling REST API wastes API quota and may miss changes between polls
import time
while True:
response = requests.get(f"{erp_host}/fscmRestApi/resources/latest/salesOrders"
f"?q=LastUpdateDate>{last_poll_time}")
process_orders(response.json())
time.sleep(60) # Burns quota; misses sub-second changes; no error handling
Correct: Subscribe to Oracle Business Events via OIC
# GOOD -- Oracle publishes Business Events on status change; OIC subscribes
OIC Integration:
Trigger: Oracle ERP Cloud Adapter
--> Business Event: oracle.apps.scm.orderManagement.orders.orderBookedEvent
Process: Extract Order Number, Status
Invoke: Salesforce REST API --> Update Opportunity
Error: Route to OIC error hospital
Wrong: Building FBDI CSV files with hardcoded column positions
# BAD -- Hardcoded column order breaks when Oracle adds/removes columns
csv_row = f"{customer_name},{address1},{city},{state},{zip},{country}"
# Column order changed in 24B release -- entire import silently fails
Correct: Use Oracle-provided FBDI template and map by column header
# GOOD -- Download template from Oracle, map by header name
template_headers = get_template_headers("CustomerInterface.csv")
row = {col: "" for col in template_headers} # Initialize all columns
row["CUSTOMER_NAME"] = sf_account["Name"][:360]
row["ADDRESS1"] = sf_account.get("BillingStreet", "")[:240]
row["ORIG_SYSTEM_REFERENCE"] = sf_account["Id"]
# Only populated columns mapped; rest stay empty -- Oracle handles defaults
Common Pitfalls
Not syncing customers before orders: Oracle ERP Cloud requires a valid Customer record before a Sales Order can reference it. Fix: always run Account-to-Customer sync first; add pre-validation lookup in order sync flow. [src4, src5]
Ignoring Oracle ERP Cloud setup data dependencies: Orders require valid Order Type, Price List, Warehouse, Shipping Method, and Payment Terms. Fix: maintain a mapping/validation table in OIC for all lookup values. [src3]
Using sandbox for load testing: Both Salesforce sandbox and Oracle test instances have lower limits than production. Fix: request full-copy sandbox (SF) and production-mirrored test pod (Oracle). [src1]
Not handling FBDI partial failures: An FBDI import of 1,000 records may succeed at job level but have 50 row-level failures. Fix: always download and parse the FBDI output log from UCM after every import. [src4, src6]
Hardcoding API versions: Salesforce API v62.0 will become v63.0 in Summer '26. Oracle 24B will become 25A. Fix: use environment variables or OIC connection properties for API versions. [src1]
Single integration user with broad permissions: Admin-level permissions for all integrations creates security and audit risk. Fix: create dedicated integration users per integration with minimum-required permissions. [src1, src3]