CPQ-to-ERP Integration: Complex Order Creation from Salesforce CPQ and Oracle CPQ
How do you integrate Salesforce CPQ or Oracle CPQ with ERP for complex order creation?
TL;DR
Bottom line: CPQ-to-ERP integration converts approved quotes into ERP sales orders. Salesforce CPQ uses the SBQQ__Quote__c.Ordered checkbox or Revenue Cloud's Order Management API; Oracle CPQ uses Commerce REST API actions (order_start, order_update) with OIC or direct REST calls to the target ERP.
Key limit: Salesforce governor limits (100 SOQL queries per transaction) are the binding constraint — complex CPQ bundles with nested products can exhaust the limit during automated order generation. Oracle CPQ throttles above ~50 concurrent REST requests.
Watch out for: Idempotency — duplicate order creation is the #1 production defect (30-40% of CPQ-to-ERP incidents). Always include an external reference ID (quote number + version) as a unique key on the ERP order.
Best for: B2B organizations with complex product configurations, tiered pricing, discount approval workflows, and multi-line orders that must flow into SAP, NetSuite, D365, or Oracle ERP Cloud as structured sales orders.
Authentication: Salesforce uses OAuth 2.0 JWT Bearer for server-to-server; Oracle CPQ uses OAuth 2.0 or basic auth with session tokens; target ERPs use their native auth.
System Profile
This integration playbook covers the CPQ-to-ERP order creation segment of the quote-to-cash cycle. It addresses two major CPQ platforms — Salesforce CPQ (including Revenue Cloud) and Oracle CPQ Cloud — and four major target ERPs: SAP S/4HANA, Oracle NetSuite, Microsoft Dynamics 365 Finance & SCM, and Oracle ERP Cloud. The focus is specifically on converting approved, fully-priced quotes into structured sales orders in the ERP, including line items, pricing, discounts, shipping, and tax classification.
System
Role
API Surface
Direction
Salesforce CPQ / Revenue Cloud
CPQ — quote authoring, pricing, approvals
REST API v66.0, SBQQ ServiceRouter, Platform Events
Outbound (source)
Oracle CPQ Cloud
CPQ — configure, price, quote
REST API v19, Commerce API, Configuration API
Outbound (source)
SAP S/4HANA
ERP — sales order management
OData v4 (A_SalesOrder), BAPI, IDoc
Inbound (target)
Oracle NetSuite
ERP — sales order management
SuiteTalk REST/SOAP, RESTlet
Inbound (target)
Microsoft Dynamics 365 F&SCM
ERP — sales order management
OData v4, Dual-write, Data Entities
Inbound (target)
iPaaS (MuleSoft / Boomi / Celigo / OIC)
Middleware — orchestration, transformation
Pre-built connectors
Orchestrator
API Surfaces & Capabilities
Salesforce CPQ / Revenue Cloud APIs
API Surface
Protocol
Best For
Max Records/Request
Rate Limit
Real-time?
Bulk?
SBQQ ServiceRouter (Apex)
Apex REST / Remoting
Quote calculation, save, read model
Governor limits
100 SOQL/txn, 150 DML/txn
Yes
No
REST API v66.0
HTTPS/JSON
CRUD on quote/order objects
200 composite
100K calls/24h (Enterprise)
Yes
No
Bulk API 2.0
HTTPS/CSV
Mass quote line export
150M per file
15K batches/24h
No
Yes
Platform Events
Bayeux/CometD
Quote/order status notifications
N/A
Edition-dependent
Yes
N/A
Revenue Cloud Order Management
HTTPS/JSON
Native order creation
Per-transaction
Shared with REST API
Yes
No
Oracle CPQ Cloud APIs
API Surface
Protocol
Best For
Max Records/Request
Rate Limit
Real-time?
Bulk?
Commerce REST API v19
HTTPS/JSON
Transaction CRUD, order actions
50 per query
Throttled (~50 concurrent)
Yes
No
Configuration REST API
HTTPS/JSON
Product configuration, BOM
Per-model
Shared with Commerce
Yes
No
Bulk Data Services (24D+)
HTTPS/CSV
Mass transaction export/import
Large batch
Separate quota
No
Yes
OIC Integration (pub/sub)
HTTPS/JSON + messaging
Event-driven ERP sync
Queue-based
OIC limits
Near-real-time
Yes
Rate Limits & Quotas
Per-Request Limits
Limit Type
Value
System
Notes
Max composite subrequests
25
Salesforce Composite API
All-or-nothing by default
Max SOQL query results
2,000 per page
Salesforce REST API
Use queryMore for pagination
Max request body size
50 MB
Salesforce REST API
Complex bundle quotes can approach this
Max collection query results
50 per page
Oracle CPQ REST API
Use offset and limit
Max OData batch subrequests
1,000
SAP S/4HANA OData
Per $batch request
Max SuiteTalk page size
1,000 records
NetSuite SuiteTalk REST
Default 100
Rolling / Daily Limits
Limit Type
Value
Window
System
API calls
100,000 (Enterprise) / 5M (Unlimited)
24h rolling
Salesforce
Bulk API batches
15,000
24h rolling
Salesforce
Concurrent long-running requests
25
Per org
Salesforce
Concurrent REST requests
5 (default) / 10 (SuiteCloud Plus)
Per account
NetSuite
OData requests
Fair-use / throttled
Per tenant
SAP S/4HANA Cloud
Dynamics 365 OData
6,000 requests/5 min per user
5-min rolling
Microsoft D365
Oracle CPQ concurrent
~50 (throttled)
Per tenant
Oracle CPQ
Transaction / Governor Limits (Salesforce)
Limit Type
Per-Transaction Value
Notes
SOQL queries
100
CPQ order generation triggers can cascade
DML statements
150
Each insert/update/delete = 1
Callouts
100
HTTP requests to external services
CPU time
10,000 ms (sync) / 60,000 ms (async)
Complex bundles are the main risk
Heap size
6 MB (sync) / 12 MB (async)
500+ line quotes can hit this
Future calls
50 per transaction
Limits parallel async processing
Authentication
System
Flow
Use When
Token Lifetime
Notes
Salesforce
OAuth 2.0 JWT Bearer
Server-to-server middleware
2h (session timeout)
Recommended; requires connected app + certificate
Oracle CPQ
OAuth 2.0 Client Credentials
Server-to-server via OIC
1h (configurable)
Standard for OIC integrations
SAP S/4HANA
OAuth 2.0 + x-csrf-token
All write operations
Token: 30 min, csrf: per-session
Must fetch csrf before POST/PATCH
NetSuite
Token-Based Auth (TBA)
Server-to-server
Does not expire
Requires integration record + token pair
Dynamics 365
OAuth 2.0 via Azure AD
All API access
Access: 1h, Refresh: 90 days
Register app in Azure AD
Authentication Gotchas
Salesforce JWT bearer flow requires a connected app with a digital certificate — self-signed works for dev, CA-signed recommended for prod. [src1]
Oracle CPQ basic auth is being phased out in favor of OAuth 2.0 — plan migration before 2027. [src2]
SAP x-csrf-token expires within the session — pooled HTTP connections each need a fresh token fetch. [src3]
NetSuite TBA tokens do not expire but can be revoked — build re-authorization alerting into middleware. [src7]
Constraints
Salesforce CPQ is sunset for new customers as of March 2025; no renewals beyond August 2026 — all new implementations must use Revenue Cloud.
CPQ pricing rules and ERP pricing must match exactly — discrepancies cause 15-40% of billing errors.
The Ordered checkbox on SBQQ__Quote__c can only be set ONCE — subsequent attempts are ignored.
Oracle CPQ Commerce actions execute server-side BML scripts that can modify transaction data.
NetSuite sales order creation requires matching internal IDs for customer, item, location, and subsidiary.
SAP BAPI_SALESORDER_CREATEFROMDAT2 requires explicit COMMIT_WORK call — the BAPI does not auto-commit.
Multi-currency orders require exchange rate synchronization between CPQ and ERP at order creation time.
Integration Pattern Decision Tree
START — Need to create ERP orders from CPQ quotes
├── Which CPQ platform?
│ ├── Salesforce CPQ (managed package)
│ │ ├── Order volume < 500/day?
│ │ │ ├── YES → SBQQ Ordered checkbox + trigger-based callout to ERP
│ │ │ └── NO → Platform Events + middleware (MuleSoft/Boomi) → ERP
│ │ └── Need real-time order creation?
│ │ ├── YES → Apex trigger on Order → callout to ERP REST API
│ │ └── NO → Scheduled batch: query new Orders → bulk push to ERP
│ ├── Salesforce Revenue Cloud
│ │ ├── Native to Salesforce ecosystem?
│ │ │ ├── YES → Revenue Cloud Order Management → Salesforce Order object
│ │ │ └── NO → Order Management API → middleware → ERP
│ │ └── Need external ERP sync?
│ │ ├── YES → Platform Events on Order creation → middleware → ERP API
│ │ └── NO → Stay within Salesforce ecosystem
│ └── Oracle CPQ Cloud
│ ├── Target ERP is Oracle ERP Cloud / Fusion?
│ │ ├── YES → Native OIC integration (pub/sub) → Order Management
│ │ └── NO ↓
│ ├── Using Oracle Integration Cloud (OIC)?
│ │ ├── YES → CPQ publishes to OIC queue → OIC transforms → ERP API
│ │ └── NO → CPQ Commerce REST → custom middleware → ERP API
│ └── Need real-time?
│ ├── YES → Commerce action triggers → synchronous integration
│ └── NO → Batch export via Bulk Data Services → scheduled import
├── Which target ERP?
│ ├── SAP S/4HANA → OData v4 (A_SalesOrder) or BAPI via RFC
│ ├── Oracle NetSuite → SuiteTalk REST (POST /salesOrder) or RESTlet
│ ├── Microsoft D365 → OData v4 (SalesOrderHeaders data entity)
│ └── Oracle ERP Cloud → REST API (fscmRestApi/resources/salesOrders)
└── Error strategy?
├── Zero-loss → idempotent key (quote# + version) + dead letter queue
└── Best-effort → retry 3x with exponential backoff, then alert
Quick Reference
Salesforce CPQ-to-ERP Order Creation Flow
Step
Source System
Action
Target System
Data Objects
Failure Handling
1
Salesforce CPQ
Quote approved → Ordered checkbox → Order auto-created
Salesforce (internal)
Order, OrderItem
Governor limit check; silent failure if exceeded
2
Salesforce
Platform Event on Order creation
Middleware
Order payload (JSON)
Retry with idempotency key
3
Middleware
Transform SF Order → ERP format
Target ERP
Mapped sales order + lines
Transform errors → dead letter queue
4
Middleware
POST sales order to ERP
SAP / NetSuite / D365
Sales order entity
429 → backoff; validation → DLQ
5
Target ERP
Return order ID
Middleware → Salesforce
ERP Order Number
Write-back to SF Order
Oracle CPQ-to-ERP Order Creation Flow
Step
Source System
Action
Target System
Data Objects
Failure Handling
1
Oracle CPQ
Quote submitted → order_start action
CPQ (internal)
Transaction (Commerce doc)
BML validation; errors block submission
2
Oracle CPQ
Publishes event to OIC queue
OIC
Transaction payload
OIC error handling + retry
3
OIC/Middleware
Transform → ERP order format
Target ERP
Sales order + lines
Transform failures → error hospital
4
Middleware
POST to ERP order API
Target ERP
Sales order
Same as SF flow
5
Target ERP
Return order ID
OIC → CPQ
Order number
Write-back via order_update
Step-by-Step Integration Guide
1. Configure Salesforce CPQ Order Generation
Set up CPQ order generation so approved quotes automatically produce Order and Order Product records. [src1, src5]
// Check quote readiness and trigger order generation
SBQQ__Quote__c quote = [
SELECT Id, SBQQ__Ordered__c, SBQQ__Primary__c, SBQQ__Status__c
FROM SBQQ__Quote__c WHERE Id = :quoteId
];
System.assert(quote.SBQQ__Primary__c == true, 'Quote must be Primary');
System.assert(quote.SBQQ__Status__c == 'Approved', 'Quote must be Approved');
quote.SBQQ__Ordered__c = true;
update quote;
// CPQ package trigger creates Order + OrderItem records automatically
Verify: SELECT Id, OrderNumber FROM Order WHERE SBQQ__Quote__c = :quoteId → expect 1 Order with Status = 'Draft'.
2. Capture Order Creation Event
Use Platform Event or Apex trigger to detect new CPQ-generated orders and push to middleware. [src1]
// Apex Trigger: Fire Platform Event on CPQ Order creation
trigger OrderCreatedTrigger on Order (after insert) {
List<CPQ_Order_Event__e> events = new List<CPQ_Order_Event__e>();
for (Order ord : Trigger.new) {
if (ord.SBQQ__Quote__c != null) {
events.add(new CPQ_Order_Event__e(
Order_Id__c = ord.Id,
Quote_Id__c = ord.SBQQ__Quote__c,
Account_Id__c = ord.AccountId
));
}
}
if (!events.isEmpty()) { EventBus.publish(events); }
}
Verify: Platform Event subscription receives event with correct Order_Id__c.
3. Transform and POST to ERP
Map Salesforce Order to target ERP schema, then create sales order. [src4, src6]
# SAP S/4HANA: Create sales order via OData v4
# Step 1: Fetch CSRF token
curl -X GET "${SAP_HOST}/sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder" \
-H "Authorization: Bearer ${SAP_TOKEN}" -H "x-csrf-token: fetch" -D -
# Step 2: POST sales order with idempotency key
curl -X POST "${SAP_HOST}/sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder" \
-H "Authorization: Bearer ${SAP_TOKEN}" \
-H "x-csrf-token: ${CSRF_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"SalesOrderType":"OR","SoldToParty":"CUST001",
"PurchaseOrderByCustomer":"SF-Q-00123-v1",
"to_Item":{"results":[{"Material":"MAT-001","RequestedQuantity":"5"}]}}'
Verify: HTTP 201 with SalesOrder number in response body.
4. Write ERP Order Number Back to Salesforce
Update Salesforce Order with ERP order number for cross-reference and audit trail. [src6]
// Write-back ERP order number to Salesforce
await sfClient.sobject('Order').update({
Id: sfOrderId,
ERP_Order_Number__c: erpOrderNumber,
ERP_Sync_Status__c: 'Synced',
ERP_Sync_Timestamp__c: new Date().toISOString()
});
Verify: SELECT ERP_Order_Number__c FROM Order WHERE Id = :sfOrderId returns ERP order number.
5. Handle Oracle CPQ-to-ERP via OIC
Use Commerce REST API's order actions, then route through Oracle Integration Cloud. [src2, src3]
# Oracle CPQ: Trigger order processing on approved transaction
curl -X POST \
"https://${CPQ_INSTANCE}.oracle.com/rest/v19/commerce/${PROCESS}/${MAIN_DOC}/${TXN_ID}/actions/order_start" \
-H "Authorization: Bearer ${ORACLE_CPQ_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"comments":"Order initiated from approved quote"}'
Verify: Transaction status changes; OIC dashboard shows integration flow execution.
Code Examples
Python: Salesforce CPQ Order to NetSuite Sales Order
# Input: Salesforce Order ID (from CPQ Ordered checkbox)
# Output: NetSuite Sales Order internal ID
from simple_salesforce import Salesforce # v1.12+
import requests
def sync_cpq_order_to_netsuite(sf_order_id, sf, ns_url, ns_headers):
order = sf.query(f"""
SELECT Id, OrderNumber, Account.NetSuite_Internal_ID__c,
(SELECT Product2.NetSuite_Item_ID__c, Quantity,
SBQQ__QuoteLine__r.SBQQ__NetPrice__c
FROM OrderItems)
FROM Order WHERE Id = '{sf_order_id}'
""")['records'][0]
ns_order = {
'entity': {'id': order['Account']['NetSuite_Internal_ID__c']},
'otherRefNum': order['OrderNumber'], # Idempotency key
'item': {'items': [{
'item': {'id': li['Product2']['NetSuite_Item_ID__c']},
'quantity': li['Quantity'],
'rate': str(li['SBQQ__QuoteLine__r']['SBQQ__NetPrice__c'])
} for li in order['OrderItems']['records']]}
}
resp = requests.post(ns_url + '/salesOrder', json=ns_order, headers=ns_headers)
if resp.status_code == 204:
return resp.headers.get('Location', '').split('/')[-1]
raise Exception(f'NetSuite error {resp.status_code}: {resp.text}')
JavaScript/Node.js: Salesforce CPQ Order to Dynamics 365
Salesforce amounts use major currency units (100.50 USD), but SAP may store in minor units for zero-decimal currencies (JPY). [src4]
Oracle CPQ custom attributes use variable name suffixes (_t for text, _l for line-level) — API field names do NOT match UI labels. [src2]
Salesforce multi-select picklists serialize as semicolon-delimited (Val1;Val2) via API — split on semicolons, not commas. [src1]
SAP S/4HANA OData returns amounts as strings — parse to decimal before comparison. [src4]
Error Handling & Failure Points
Common Error Codes
Code
System
Meaning
Resolution
429
SF, NetSuite, D365
Rate limit exceeded
Exponential backoff; check Retry-After header
INVALID_FIELD
Salesforce
Field not writable
Verify SBQQ__ namespace; check FLS
UNABLE_TO_LOCK_ROW
Salesforce
Record locked
Retry with random jitter (500-2000ms)
403 + csrf error
SAP S/4HANA
CSRF token missing/expired
Fetch new token before retry
DUPLICATE_VALUE
NetSuite
Duplicate external ID
Log as success — order already exists
SSS_REQUEST_LIMIT_EXCEEDED
NetSuite
Governance limit
Wait for next window; optimize scripts
INVALID_SESSION_ID
SF, Oracle CPQ
Session expired
Refresh token and retry
Failure Points in Production
Silent order generation failure: Setting Ordered = true with 100+ line quotes can hit governor limits — no error thrown, checkbox stays true, but no Order created. Fix: Scheduled job to detect Ordered quotes without linked Orders. [src5]
Duplicate ERP orders: Middleware retries after timeout, but first request succeeded. Fix: Always include quote number + version as idempotency key; check before creating. [src4]
Currency mismatch: CPQ in EUR, ERP customer in USD — order created with wrong amounts. Fix: Validate currency match before order creation; include exchange rate from CPQ. [src4]
NetSuite customer not found: First-time customer not synced yet. Fix: Customer sync before order sync; if lookup fails, create customer first (saga pattern). [src7]
SAP BAPI silent failure: BAPI returns RETURN table with errors but HTTP 200. Fix: Always parse RETURN table; TYPE = 'E' or 'A' means failure. [src4]
Oracle CPQ BML modifies data: Commerce actions can change pricing before order reaches ERP. Fix: Post-action validation: compare CPQ total vs ERP total; alert if delta > 1%. [src2]
Anti-Patterns
Wrong: Polling Salesforce for new orders every 60 seconds
// BAD — wastes API calls, high latency, misses rapid order creation
setInterval(async () => {
const newOrders = await sf.query(
"SELECT Id FROM Order WHERE CreatedDate > LAST_N_MINUTES:1"
);
for (const order of newOrders.records) { await pushToERP(order.Id); }
}, 60000);
Correct: Use Platform Events for real-time, event-driven sync
// GOOD — real-time, no polling, no wasted API calls
const faye = require('faye');
const client = new faye.Client(sf.instanceUrl + '/cometd/66.0');
client.subscribe('/event/CPQ_Order_Event__e', async (message) => {
await pushToERP(message.data.payload.Order_Id__c);
});
// BAD — blocks trigger, governor limits, mixed DML
trigger OrderTrigger on Order (after insert) {
for (Order ord : Trigger.new) {
Http h = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint('https://erp.example.com/api/order');
req.setMethod('POST');
h.send(req); // Synchronous callout in trigger = BAD
}
}
Correct: Use Queueable for async callouts
// GOOD — async processing, respects governor limits
trigger OrderTrigger on Order (after insert) {
Set<Id> orderIds = new Set<Id>();
for (Order ord : Trigger.new) {
if (ord.SBQQ__Quote__c != null) orderIds.add(ord.Id);
}
if (!orderIds.isEmpty())
System.enqueueJob(new ERPOrderSyncQueueable(orderIds));
}
Common Pitfalls
Ordered checkbox is one-shot: Cannot re-trigger by toggling off/on. Fix: Build recovery job: query quotes where Ordered=true but no linked Order exists. [src5]
API version mismatch: CPQ managed package API version differs from custom code. Fix: Pin all integration code to same API version as CPQ package. [src1]
NetSuite subsidiary mismatch: Multi-subsidiary accounts need matching subsidiary on order. Fix: Map SF business unit to NetSuite subsidiary in customer sync. [src7]
SAP pricing condition types: SAP uses PR00, K004, ZDISC — not simple price + discount. Fix: Decompose CPQ net price into SAP condition type structure. [src4]
D365 number sequence exhaustion: High-volume integration exhausts pre-allocated ranges. Fix: Use continuous (not pre-allocated) number sequences for sales orders. [src4]
Oracle CPQ variable name opacity: API field names use suffixes (_t, _l) that differ from UI labels. Fix: Always reference CPQ Admin Setup for variable names. [src2]
Diagnostic Commands
# Check if CPQ order was generated from quote (Salesforce)
curl -s "${SF_INSTANCE}/services/data/v66.0/query?q=SELECT+Id,OrderNumber,Status+FROM+Order+WHERE+SBQQ__Quote__c='${QUOTE_ID}'" \
-H "Authorization: Bearer ${SF_TOKEN}" | jq '.records'
# Check Salesforce API usage / remaining limits
curl -s "${SF_INSTANCE}/services/data/v66.0/limits" \
-H "Authorization: Bearer ${SF_TOKEN}" | jq '{DailyApiRequests}'
# Check Oracle CPQ transaction status
curl -s "https://${CPQ_INSTANCE}.oracle.com/rest/v19/commerce/${PROCESS}/${MAIN_DOC}/${TXN_ID}" \
-H "Authorization: Bearer ${ORACLE_CPQ_TOKEN}" | jq '{status: ._status, total: .totalPrice_t}'
# Search SAP for order by PO number (SF order number)
curl -s "${SAP_HOST}/sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder?\$filter=PurchaseOrderByCustomer%20eq%20'${SF_ORDER_NUMBER}'" \
-H "Authorization: Bearer ${SAP_TOKEN}" | jq '.d.results'
# Search NetSuite for order by external reference
curl -s "https://${NS_ACCOUNT}.suitetalk.api.netsuite.com/services/rest/record/v1/salesOrder?q=otherRefNum%20IS%20%22${SF_ORDER_NUMBER}%22" \
-H "Authorization: Bearer ${NS_TOKEN}" | jq '.items'
# Check D365 sales order
curl -s "${D365_URL}/data/SalesOrderHeadersV2?\$filter=SalesOrderNumber%20eq%20'${SF_ORDER_NUMBER}'" \
-H "Authorization: Bearer ${D365_TOKEN}" | jq '.value'
Version History & Compatibility
Component
Version
Release Date
Status
Key Changes
Salesforce CPQ (managed package)
v66.0 (Spring '26)
2026-02
Current (sunset announced)
Last major release; Revenue Cloud migration tools
Salesforce Revenue Cloud
Spring '26
2026-02
Current (GA)
Order Management API v2; multi-currency
Oracle CPQ REST API
v19 (24D)
2025-12
Current
Bulk Data Services; enhanced Commerce actions
SAP S/4HANA API
2408
2024-08
Current
Async OData; enhanced A_SalesOrder
NetSuite SuiteTalk REST
2024.2
2024-09
Current
Enhanced SuiteQL for complex queries
D365 F&SCM
10.0.39
2025-04
Current
SalesOrderHeadersV2 improvements
When to Use / When Not to Use
Use When
Don't Use When
Use Instead
B2B with complex product configuration and approval workflows
Simple B2C eCommerce cart orders
business/erp-integration/ecommerce-to-erp/2026
Multi-line quotes with bundles and negotiated pricing
Single-product fixed-price orders
Direct ERP order entry or simple webhook
CPQ approvals and discount governance must be preserved in ERP
No pricing complexity — ERP prices are authoritative
Skip CPQ; create orders directly in ERP
Need bidirectional status sync (order → fulfillment → CPQ)
One-way push without status tracking
Simple REST POST
Multi-currency, multi-entity orders
Single-currency, single-entity
Simplified integration without FX handling
Cross-System Comparison
Capability
Salesforce CPQ
Salesforce Revenue Cloud
Oracle CPQ Cloud
Notes
Order generation trigger
Ordered checkbox on quote
Order Management API
Commerce action (order_start)
SF CPQ is declarative; Oracle is API-driven
API style
REST (sObject CRUD)
REST (Order Mgmt API)
Commerce REST API v19
Revenue Cloud API is newer
Pricing engine
Apex (managed package)
Salesforce native
Server-side BML
CPQ pricing must match ERP pricing
Native ERP integration
None (middleware required)
Salesforce-native only
Oracle ERP Cloud via OIC
Oracle CPQ + Oracle ERP = strongest native
Middleware options
MuleSoft, Boomi, Workato, Celigo
Same + native connectors
OIC, MuleSoft, Boomi
OIC recommended for Oracle CPQ
Rate limit
100K API calls/24h (Enterprise)
Shared with REST API
Throttled (~50 concurrent)
SF has most transparent limits
Bulk order support
Bulk API 2.0
Bulk API 2.0
Bulk Data Services (24D+)
All support high volume
Sunset risk
Sunset Mar 2025 / Aug 2026
Active (successor)
Active
SF CPQ customers must plan migration
Multi-currency
Salesforce MCE
Native
Built-in engine
All support multi-currency
Approval workflow
SF Approvals + CPQ Advanced
Flow-based
CPQ workflow engine
All have approval capabilities
Important Caveats
Salesforce CPQ is being sunset — no new customer sales since March 2025, no renewals beyond August 2026. All new implementations should use Revenue Cloud.
CPQ-to-ERP pricing parity is non-negotiable: budget 20-30% of integration effort for pricing reconciliation.
Sandbox/test environments have different rate limits than production across all platforms — load test with production-volume data.
Oracle CPQ REST API field names use variable name suffixes (_t, _l, _qt) that do not match UI labels.
Governor limits in Salesforce are per-transaction — a 200-line order with triggers can consume 80+ SOQL queries in one transaction.
This card covers order creation only. For billing, invoicing, and revenue recognition, see quote-to-cash-integration and subscription-billing-integration.