---
# === IDENTITY ===
id: business/erp-integration/supplier-portal-srm-integration/2026
canonical_question: "How do you integrate ERP with supplier portals like Ariba, Coupa, or Jaggaer for SRM?"
aliases:
  - "ERP to supplier portal integration using cXML and OCI punch-out"
  - "How to connect SAP Ariba, Coupa, or Jaggaer with your ERP for procurement"
  - "Supplier relationship management platform integration playbook for ERP systems"
  - "End-to-end SRM integration — supplier onboarding through invoice flip"
entity_type: erp_integration
domain: business > erp-integration > supplier-portal-srm-integration
region: global
jurisdiction: global
temporal_scope: 2024-2026

# === SYSTEM PROFILE ===
systems:
  - name: "SAP Ariba"
    vendor: "SAP"
    version: "2502"
    edition: "Cloud"
    deployment: cloud
    api_surface: "cXML, OCI, REST, SOAP"
  - name: "Coupa"
    vendor: "Coupa (Thoma Bravo)"
    version: "R35"
    edition: "Business Spend Management"
    deployment: cloud
    api_surface: "REST, cXML, CSV"
  - name: "Jaggaer ONE"
    vendor: "Jaggaer"
    version: "2024.2"
    edition: "Enterprise"
    deployment: cloud
    api_surface: "REST, cXML, OCI, SFTP"
  - name: "SAP S/4HANA"
    vendor: "SAP"
    version: "2408"
    edition: "Cloud / On-Premise"
    deployment: hybrid
    api_surface: "OData v4, BAPI/RFC, IDoc"
  - name: "Oracle ERP Cloud"
    vendor: "Oracle"
    version: "24B"
    edition: "Enterprise"
    deployment: cloud
    api_surface: "REST, SOAP, FBDI"

# === VERIFICATION ===
last_verified: 2026-03-03
confidence: 0.85
version: 1.0
first_published: 2026-03-03

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: evolving
  last_breaking_change: "SAP Ariba CIG renamed to SAP Integration Suite, managed gateway for spend management (2025); Coupa token-based supplier portal access (Jan 2026)"
  next_review: 2026-08-30
  change_sensitivity: high

# === CONSTRAINTS ===
constraints:
  - "Punch-out catalogs require HTTPS — HTTP endpoints are rejected by all major SRM platforms"
  - "cXML SharedSecret credentials must be exchanged out-of-band — no automated provisioning API exists on Ariba Network"
  - "Supplier master sync must complete before transactional docs flow — orphan POs cause cascading failures in 3-way match"
  - "OCI protocol (SAP) is limited to cart transfer only — no order confirmation, ASN, or invoice support via OCI"
  - "Coupa API rate limits: 50 requests/minute for non-integration users, custom limits for certified integrations"
  - "Ariba Network supplier enablement requires separate registration per buyer — no global supplier ID portability"
  - "cXML invoice flip (PO-flip) requires exact line-item match — partial invoicing needs manual cXML OrderReference construction"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "User needs only internal procurement approval workflow without external supplier portal"
    use_instead: "business/erp-integration/procure-to-pay-integration/2026"
  - condition: "User needs only AP invoice automation without supplier portal"
    use_instead: "business/erp-integration/invoice-to-pay-ap-automation/2026"
  - condition: "User needs iPaaS platform comparison for general ERP integration"
    use_instead: "business/erp-integration/ipaas-platform-comparison/2026"

# === AGENT HINTS ===
inputs_needed:
  - key: srm_platform
    question: "Which SRM / procurement platform are you integrating with?"
    type: choice
    options:
      - "SAP Ariba"
      - "Coupa"
      - "Jaggaer"
      - "GEP SMART"
      - "Other / multiple"
  - key: integration_scope
    question: "What procurement processes need integration?"
    type: choice
    options:
      - "Punch-out catalog only"
      - "PO transmission + order confirmation"
      - "Full P2P (punch-out + PO + ASN + invoice + payment)"
      - "Supplier onboarding + vendor master sync"
  - key: erp_system
    question: "Which ERP system is on the other side?"
    type: choice
    options:
      - "SAP S/4HANA or ECC"
      - "Oracle ERP Cloud"
      - "NetSuite"
      - "Microsoft Dynamics 365"
      - "Other"
  - key: integration_method
    question: "What integration method do you prefer?"
    type: choice
    options:
      - "cXML direct (point-to-point)"
      - "OCI (SAP environments)"
      - "iPaaS middleware (MuleSoft, Boomi, Workato)"
      - "EDI/VAN"

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/business/erp-integration/supplier-portal-srm-integration/2026"
suggested_citation: "Source: knowledgelib.io — AI Knowledge Library (verified 2026-03-03)"

# === RELATED UNITS ===
related_kos:
  depends_on:
    - id: "business/erp-integration/master-data-management-erp/2026"
      label: "Master Data Management for ERP — vendor master sync patterns"
  related_to:
    - id: "business/erp-integration/procure-to-pay-integration/2026"
      label: "Procure-to-Pay Integration — full P2P flow including matching and payment"
    - id: "business/erp-integration/invoice-to-pay-ap-automation/2026"
      label: "Invoice-to-Pay AP Automation — downstream invoice processing"
  solves:
    - id: "business/erp-integration/order-to-cash-integration/2026"
      label: "Order-to-Cash — supplier-side view of the same transaction"
  alternative_to:
    - id: "business/erp-integration/sap-idoc-edi-integration/2026"
      label: "SAP IDoc/EDI — traditional EDI-based procurement without SRM portal"
  often_confused_with:
    - id: "business/erp-integration/procure-to-pay-integration/2026"
      label: "Procure-to-Pay — covers internal requisition-to-payment; this card covers the external supplier portal layer"

# === SOURCES ===
sources:
  - id: src1
    title: "SAP Ariba Integration with S/4HANA — Complete Guide"
    author: DataLark
    url: https://datalark.com/blog/sap-ariba-s4hana-integration
    type: technical_blog
    published: 2025-11-15
    reliability: high
  - id: src2
    title: "Coupa Integration Technical Documentation — Purchase Orders and Punchouts"
    author: Coupa
    url: https://compass.coupa.com/en-us/products/product-documentation/supplier-resources/for-suppliers/integration-resources/purchase-orders-and-punchouts
    type: official_docs
    published: 2025-12-01
    reliability: authoritative
  - id: src3
    title: "cXML & OCI: Overview of PunchOut Document Languages"
    author: ControlHub
    url: https://www.controlhub.com/blog/cxml-oci-punchout-languages
    type: technical_blog
    published: 2025-06-20
    reliability: moderate_high
  - id: src4
    title: "JAGGAER ONE Integrations — Seamless ERP & API Integration"
    author: Jaggaer
    url: https://www.jaggaer.com/solutions/integrations
    type: official_docs
    published: 2025-10-01
    reliability: authoritative
  - id: src5
    title: "SAP Ariba Cloud Integration Gateway (CIG) Overview"
    author: SAP Community
    url: https://blogs.sap.com/2018/06/19/ariba-cig-add-on-series-cig-overview/
    type: technical_blog
    published: 2024-08-10
    reliability: high
  - id: src6
    title: "PunchOut Integration: Streamline B2B Procurement with cXML & OCI"
    author: PunchOutLink
    url: https://punchoutlink.com/punchout-integration-guide/
    type: technical_blog
    published: 2025-09-15
    reliability: moderate_high
  - id: src7
    title: "ERP for Supplier Management: How SRM Software Complements Your ERP"
    author: Kodiak Hub
    url: https://www.kodiakhub.com/blog/erp-for-supplier-management-how-srm-software-complements-your-erp
    type: technical_blog
    published: 2025-07-22
    reliability: moderate_high
  - id: src8
    title: "How to Integrate SAP Ariba with Your ERP System Efficiently"
    author: Procuros
    url: https://procuros.io/blog/how-to-integrate-with-sap
    type: technical_blog
    published: 2025-08-01
    reliability: moderate_high
---

# ERP-to-Supplier Portal SRM Integration Playbook (Ariba, Coupa, Jaggaer)

## TL;DR

- **Bottom line**: Integrate ERP with SRM portals via cXML (Ariba, Coupa, Jaggaer) or OCI (SAP-only) for punch-out catalogs, PO transmission, and invoice flip — middleware (CIG, iPaaS) handles protocol translation and vendor master sync.
- **Key limit**: cXML is the universal SRM protocol but only covers transactional documents; vendor master sync always requires separate REST/SOAP APIs or file-based integration.
- **Watch out for**: Supplier master data must be synchronized before any PO or invoice flows — orphan transactions break 3-way matching and cause payment blocks.
- **Best for**: Organizations with 50+ suppliers on procurement portals needing automated requisition-to-payment with real-time catalog pricing and order confirmation.
- **Authentication**: cXML uses SharedSecret (HMAC-style) for document exchange; REST APIs use OAuth 2.0; OCI uses HTTP POST with session tokens.

## System Profile

This playbook covers integration between ERP systems (SAP S/4HANA, Oracle ERP Cloud, Dynamics 365) and the three dominant SRM/procurement platforms: SAP Ariba, Coupa, and Jaggaer ONE. It addresses the full supplier interaction lifecycle from punch-out catalog browsing through PO transmission, order confirmation, advance ship notice (ASN), invoice flip, and 3-way match. GEP SMART follows similar cXML patterns but is not covered in detail.

This card does NOT cover internal procurement workflows (see procure-to-pay-integration) or iPaaS platform selection (see ipaas-platform-comparison). It focuses on the external supplier portal integration layer — the protocols, data flows, and failure patterns specific to SRM-to-ERP connectivity.

| System | Role | API Surface | Direction |
|---|---|---|---|
| **SAP Ariba** | SRM portal — punch-out, sourcing, supplier management | cXML, OCI, REST, SOAP | Bidirectional |
| **Coupa** | BSM platform — procurement, invoicing, expenses | REST API, cXML, CSV/SFTP | Bidirectional |
| **Jaggaer ONE** | Source-to-pay — catalogs, contracts, supplier mgmt | REST, cXML, OCI, SFTP | Bidirectional |
| **SAP S/4HANA** | ERP — financial master, PO system of record | OData v4, BAPI/RFC, IDoc | Inbound/Outbound |
| **Oracle ERP Cloud** | ERP — procurement + AP module | REST, SOAP, FBDI | Inbound/Outbound |
| **Middleware (CIG/iPaaS)** | Protocol translation, mapping, orchestration | N/A | Orchestrator |

## API Surfaces & Capabilities

| API Surface | Protocol | Platform | Best For | Real-time? | Bulk? | Bidirectional? |
|---|---|---|---|---|---|---|
| cXML | HTTPS/XML | Ariba, Coupa, Jaggaer | PO, Invoice, ASN, Punch-out | Yes | No | Yes |
| OCI 5.0 | HTTP POST/GET (JSON in 5.0) | SAP Ariba (SAP ERPs) | Punch-out catalog only | Yes | No | One-way (cart return) |
| Ariba REST API | HTTPS/JSON | SAP Ariba | Supplier management, sourcing events | Yes | Limited | Yes |
| Ariba SOAP/Web Services | HTTPS/XML | SAP Ariba | Document export, reporting | Yes | Yes (batched) | Outbound only |
| Coupa REST API | HTTPS/JSON | Coupa | CRUD on all objects (suppliers, POs, invoices) | Yes | Yes (paging) | Yes |
| Coupa CSV/SFTP | SFTP/CSV | Coupa | Bulk supplier import, catalog loads | No | Yes | Inbound only |
| Jaggaer REST API | HTTPS/JSON | Jaggaer ONE | Custom integrations, supplier data | Yes | Limited | Yes |
| CIG (SAP Integration Suite) | IDoc/Proxy to cXML | SAP Ariba + SAP ERP | Automated PO/invoice translation | Near real-time | Yes | Yes |

## Rate Limits & Quotas

### Per-Request Limits

| Limit Type | Value | Platform | Notes |
|---|---|---|---|
| cXML document size | 5 MB | Ariba Network | Larger POs must split line items across multiple documents |
| Coupa REST API payload | 10 MB | Coupa | Applies to POST/PUT request body |
| Coupa paging limit | 50 records/page | Coupa | Use offset pagination; no cursor-based option |
| Jaggaer REST response | 1,000 records/page | Jaggaer ONE | Configurable per endpoint |
| OCI cart transfer | No formal limit | SAP OCI | Practical limit ~5,000 line items per cart session |

[src2, src4]

### Rolling / Daily Limits

| Limit Type | Value | Window | Platform |
|---|---|---|---|
| Coupa API calls | 50 req/min (standard) | Per minute | Coupa — certified integrations get higher limits |
| Ariba REST API | Throttled / fair-use | Per org | SAP Ariba — no published hard limit; 429 returned on abuse |
| Jaggaer REST API | Customer-configurable | Per tenant | Jaggaer ONE — defaults vary by contract |
| CIG throughput | 1,000 IDocs/hour (default) | Per hour | CIG — tunable via BTP configuration |
| Ariba Network document processing | Near real-time | Continuous | Documents queue when supplier endpoints are down; retry 72h |

[src5, src8]

## Authentication

| Flow | Platform | Use When | Token Lifetime | Notes |
|---|---|---|---|---|
| cXML SharedSecret | Ariba, Coupa, Jaggaer | Document exchange (PO, invoice, punch-out) | Per-request (no session) | Credentials in cXML Header; HMAC validation |
| OAuth 2.0 Client Credentials | Coupa REST API | Server-to-server API calls | 24h access token | `grant_type=client_credentials` to `/oauth2/token` |
| OAuth 2.0 + API Key | SAP Ariba REST | Supplier mgmt, sourcing API | Session-based | Requires Ariba developer portal registration |
| OAuth 2.0 + SAML | Jaggaer REST | Enterprise SSO-enabled orgs | Configurable | SAML assertion exchanged for bearer token |
| OCI Session | SAP OCI | Punch-out from SAP ERP | Browser session | HTTP POST with `HOOK_URL` and `OCI_VERSION` params |
| CIG Certificate | SAP CIG | IDoc-to-cXML translation | Certificate-based | X.509 client cert on SAP BTP subaccount |

[src1, src5, src6]

### Authentication Gotchas

- cXML SharedSecrets are NOT rotated automatically — most SRM platforms have no API for credential rotation. Build manual rotation schedules (quarterly recommended). [src6]
- Coupa OAuth tokens are scoped per instance — multi-instance deployments (sandbox + production) require separate client credentials, and tokens are not transferable. [src2]
- Ariba Network supplier authentication is per-buyer-relationship — a supplier must configure credentials separately for each buyer they trade with. [src8]
- OCI punch-out sessions inherit the ERP user's browser session — session timeout causes silent punch-out failure with no error returned to the ERP. [src3]

## Constraints

- cXML is the only protocol supported by all three major SRM platforms (Ariba, Coupa, Jaggaer) — OCI is SAP-only and limited to punch-out.
- Vendor master synchronization requires a dedicated integration separate from transactional cXML — no SRM platform supports vendor master CRUD via cXML.
- PO number cross-referencing is mandatory — the SRM platform PO ID and the ERP PO number must be mapped bidirectionally for invoice matching.
- cXML invoice flip (PO-flip) requires exact line-item matching — partial invoices or consolidated invoices across multiple POs need custom cXML construction.
- Ariba Network supplier enablement is a manual process per buyer — there is no bulk API to onboard suppliers to a buyer's Ariba Network account.
- Tax calculation timing varies by jurisdiction — some flows calculate tax in the SRM platform (at requisition), others in the ERP (at PO or invoice). Mismatch causes 3-way match failures.
- Coupa's free supplier portal has limited integration capabilities — full cXML and API access requires the supplier to have a paid Coupa integration or use the Coupa Supplier Portal (CSP) with buyer-side enablement.

## Integration Pattern Decision Tree

```
START — User needs to integrate ERP with SRM supplier portal
├── Which SRM platform?
│   ├── SAP Ariba
│   │   ├── ERP is SAP S/4HANA or ECC?
│   │   │   ├── YES → Use CIG (SAP Integration Suite, managed gateway)
│   │   │   │   └── CIG handles IDoc ↔ cXML translation automatically
│   │   │   └── NO → Use cXML direct or iPaaS middleware
│   │   └── Punch-out only?
│   │       ├── SAP ERP → OCI 5.0 (simpler, SAP-native)
│   │       └── Non-SAP ERP → cXML PunchOutSetupRequest
│   ├── Coupa
│   │   ├── Need real-time API access?
│   │   │   ├── YES → Coupa REST API (OAuth 2.0)
│   │   │   └── NO → cXML for documents, CSV/SFTP for bulk
│   │   └── Punch-out?
│   │       └── cXML PunchOutSetupRequest (Coupa-standard)
│   └── Jaggaer ONE
│       ├── cXML for transactional documents
│       ├── REST API for supplier management
│       └── OCI for SAP punch-out (if SAP ERP)
├── What scope?
│   ├── Punch-out catalog only → cXML PunchOutSetupRequest/Response + PunchOutOrderMessage
│   ├── PO transmission → cXML OrderRequest
│   ├── PO + confirmation → cXML OrderRequest + ConfirmationRequest
│   ├── Full P2P (punch-out + PO + ASN + invoice)
│   │   ├── cXML: PunchOutSetup + OrderRequest + ShipNoticeRequest + InvoiceDetailRequest
│   │   └── Middleware recommended for orchestration + error handling
│   └── Supplier onboarding / vendor master sync
│       └── REST API (not cXML) + MDM middleware
├── Integration method?
│   ├── cXML direct (point-to-point) → simplest, no middleware cost
│   ├── CIG (SAP-to-Ariba) → pre-built mappings, managed service
│   ├── iPaaS (MuleSoft, Boomi, Workato) → multi-platform, custom logic
│   └── EDI/VAN → legacy suppliers without cXML capability
└── Error tolerance?
    ├── Zero-loss → implement idempotency keys + dead letter queue + reconciliation jobs
    └── Best-effort → cXML with retry + email alerts on failure
```

## Quick Reference

### Procure-to-Pay Document Flow (SRM ↔ ERP)

| Step | Source | cXML Document | Target | ERP Object | Failure Handling |
|---|---|---|---|---|---|
| 1. Punch-out browse | ERP user | PunchOutSetupRequest | SRM portal | — | Timeout → retry; auth failure → re-register SharedSecret |
| 2. Cart return | SRM portal | PunchOutOrderMessage | ERP | Purchase Requisition | Parse error → reject cart; log cXML payload |
| 3. Requisition approval | ERP | — (internal workflow) | ERP | Approved Requisition | — |
| 4. PO transmission | ERP | cXML OrderRequest | SRM portal | Purchase Order | 4xx → fix payload; 5xx → retry 3x with backoff |
| 5. Order confirmation | SRM portal | cXML ConfirmationRequest | ERP | PO Confirmation | Partial confirm → update PO lines; reject → alert buyer |
| 6. Advance Ship Notice | SRM portal | cXML ShipNoticeRequest | ERP | Goods Receipt (partial) | Missing ASN → manual receipt; duplicate → idempotency check |
| 7. Goods receipt | ERP | — (internal, or triggered by ASN) | ERP | Goods Receipt | Receipt without PO → block; receipt > PO qty → tolerance check |
| 8. Invoice submission | Supplier | cXML InvoiceDetailRequest | SRM portal | Supplier Invoice | Validation fail → reject back to supplier with error codes |
| 9. Invoice flip to ERP | SRM portal | REST API / file / IDoc | ERP | AP Invoice | 3-way match fail → exception queue; tolerance → auto-approve |
| 10. Payment | ERP | — (payment run) | Bank / SRM | Payment Advice | Remittance advice via cXML PaymentRemittanceRequest (optional) |

## Step-by-Step Integration Guide

### 1. Establish SRM platform connectivity and credentials

Register your organization on the SRM platform's network (Ariba Network, Coupa Supplier Portal, or Jaggaer). Exchange cXML SharedSecrets with trading partners. For SAP-to-Ariba, deploy the CIG add-on on SAP BTP. [src1, src5]

```bash
# Test cXML connectivity to Ariba Network (replace with your credentials)
curl -X POST https://service.ariba.com/service/transaction/cxml.asp \
  -H "Content-Type: text/xml" \
  -d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.050/cXML.dtd">
<cXML payloadID="test-001@buyer.com" timestamp="2026-03-03T10:00:00+00:00">
  <Header>
    <From><Credential domain="NetworkId"><Identity>AN01234567890</Identity></Credential></From>
    <To><Credential domain="NetworkId"><Identity>AN09876543210</Identity></Credential></To>
    <Sender>
      <Credential domain="NetworkId">
        <Identity>AN01234567890</Identity>
        <SharedSecret>your-shared-secret</SharedSecret>
      </Credential>
      <UserAgent>ERP-Integration/1.0</UserAgent>
    </Sender>
  </Header>
  <Request>
    <ProfileRequest/>
  </Request>
</cXML>'

# Expected: HTTP 200 with cXML ProfileResponse listing supported document types
```

**Verify**: HTTP 200 response with `<ProfileResponse>` containing supported transaction types (OrderRequest, InvoiceDetailRequest, etc.)

### 2. Configure punch-out catalog (cXML PunchOutSetupRequest)

When an ERP user clicks a supplier catalog link, the ERP sends a PunchOutSetupRequest to the SRM platform. The supplier's e-commerce site authenticates the request and returns a URL for the user to browse products. [src2, src6]

```xml
<!-- cXML PunchOutSetupRequest — sent from ERP to SRM platform -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.050/cXML.dtd">
<cXML payloadID="punchout-setup-123@buyer.com"
      timestamp="2026-03-03T10:05:00+00:00">
  <Header>
    <From>
      <Credential domain="DUNS">
        <Identity>123456789</Identity>
      </Credential>
    </From>
    <To>
      <Credential domain="DUNS">
        <Identity>987654321</Identity>
      </Credential>
    </To>
    <Sender>
      <Credential domain="NetworkId">
        <Identity>buyer-system-id</Identity>
        <SharedSecret>buyer-shared-secret</SharedSecret>
      </Credential>
      <UserAgent>SAP-S4HANA/2408</UserAgent>
    </Sender>
  </Header>
  <Request deploymentMode="production">
    <PunchOutSetupRequest operation="create">
      <BuyerCookie>session-token-abc-123</BuyerCookie>
      <BrowserFormPost>
        <URL>https://erp.buyer.com/punchout/return</URL>
      </BrowserFormPost>
      <Contact>
        <Name xml:lang="en">John Buyer</Name>
        <Email>john.buyer@company.com</Email>
      </Contact>
      <SupplierSetup>
        <URL>https://supplier.example.com/cxml/punchout</URL>
      </SupplierSetup>
    </PunchOutSetupRequest>
  </Request>
</cXML>
```

**Verify**: Response contains `<PunchOutSetupResponse>` with status code 200 and a `<StartPage><URL>` pointing to the supplier catalog.

### 3. Handle cart return (PunchOutOrderMessage)

When the user checks out on the supplier site, a PunchOutOrderMessage is POSTed back to the ERP's `BrowserFormPost URL`. The ERP parses this to create a purchase requisition. [src2, src3]

```xml
<!-- PunchOutOrderMessage — returned from supplier catalog to ERP -->
<cXML payloadID="cart-return-456@supplier.com"
      timestamp="2026-03-03T10:15:00+00:00">
  <Message>
    <PunchOutOrderMessage>
      <BuyerCookie>session-token-abc-123</BuyerCookie>
      <PunchOutOrderMessageHeader operationAllowed="create">
        <Total>
          <Money currency="USD">2450.00</Money>
        </Total>
      </PunchOutOrderMessageHeader>
      <ItemIn quantity="50">
        <ItemID>
          <SupplierPartID>WIDGET-A100</SupplierPartID>
          <SupplierPartAuxiliaryID>config-standard</SupplierPartAuxiliaryID>
        </ItemID>
        <ItemDetail>
          <UnitPrice><Money currency="USD">49.00</Money></UnitPrice>
          <Description xml:lang="en">Industrial Widget A100</Description>
          <UnitOfMeasure>EA</UnitOfMeasure>
          <Classification domain="UNSPSC">31161500</Classification>
        </ItemDetail>
      </ItemIn>
    </PunchOutOrderMessage>
  </Message>
</cXML>
```

**Verify**: ERP creates a purchase requisition with correct line items, quantities, unit prices, and UNSPSC classifications matching the cart.

### 4. Transmit purchase order via cXML OrderRequest

After requisition approval, the ERP generates a PO and sends it to the SRM platform (or directly to the supplier) as a cXML OrderRequest. [src1, src2]

```xml
<!-- cXML OrderRequest — sent from ERP to supplier via SRM network -->
<cXML payloadID="po-789@buyer.com"
      timestamp="2026-03-03T10:30:00+00:00">
  <Header><!-- Same credential structure as PunchOutSetupRequest --></Header>
  <Request>
    <OrderRequest>
      <OrderRequestHeader orderID="PO-2026-00789" orderDate="2026-03-03"
                          type="new">
        <Total><Money currency="USD">2450.00</Money></Total>
        <ShipTo>
          <Address>
            <Name xml:lang="en">Warehouse Alpha</Name>
            <PostalAddress>
              <Street>123 Industrial Blvd</Street>
              <City>Chicago</City>
              <State>IL</State>
              <PostalCode>60601</PostalCode>
              <Country isoCountryCode="US">United States</Country>
            </PostalAddress>
          </Address>
        </ShipTo>
        <BillTo>
          <Address>
            <Name xml:lang="en">Buyer Corp — AP Dept</Name>
          </Address>
        </BillTo>
        <Payment>
          <PCard number="" expiration=""/>
        </Payment>
      </OrderRequestHeader>
      <ItemOut quantity="50" lineNumber="1">
        <ItemID>
          <SupplierPartID>WIDGET-A100</SupplierPartID>
        </ItemID>
        <ItemDetail>
          <UnitPrice><Money currency="USD">49.00</Money></UnitPrice>
          <Description xml:lang="en">Industrial Widget A100</Description>
          <UnitOfMeasure>EA</UnitOfMeasure>
          <Classification domain="UNSPSC">31161500</Classification>
        </ItemDetail>
      </ItemOut>
    </OrderRequest>
  </Request>
</cXML>
```

**Verify**: SRM platform returns cXML Response with `<Status code="200" text="OK"/>`. Supplier receives PO in their portal.

### 5. Process order confirmation and ASN

The supplier confirms the order via cXML ConfirmationRequest and later sends a ShipNoticeRequest (ASN). Both documents flow through the SRM network back to the ERP. [src1, src4]

```python
# Python: Parse inbound cXML ConfirmationRequest and update ERP PO status
# Input:  Raw cXML ConfirmationRequest from SRM platform webhook/polling
# Output: Updated PO status in ERP

from lxml import etree
import requests

def process_order_confirmation(cxml_payload: str, erp_api_url: str, erp_token: str):
    """Parse cXML ConfirmationRequest and update ERP PO."""
    root = etree.fromstring(cxml_payload.encode('utf-8'))
    ns = {'cxml': 'http://www.w3.org/1999/xhtml'}  # cXML uses default namespace

    confirm_header = root.find('.//ConfirmationRequest/ConfirmationHeader')
    po_number = confirm_header.get('invoiceID')  # Maps to original PO
    confirm_type = confirm_header.get('type')  # accept, reject, backordered

    line_confirmations = []
    for item in root.findall('.//ConfirmationItem'):
        line = {
            'line_number': item.get('lineNumber'),
            'quantity': item.get('quantity'),
            'status': confirm_type
        }
        line_confirmations.append(line)

    # Update ERP PO via API
    erp_response = requests.patch(
        f"{erp_api_url}/purchase-orders/{po_number}/confirmations",
        headers={"Authorization": f"Bearer {erp_token}",
                 "Content-Type": "application/json"},
        json={"confirmations": line_confirmations,
              "confirmation_type": confirm_type}
    )
    erp_response.raise_for_status()
    return erp_response.json()
```

**Verify**: PO status in ERP updates to "Confirmed" (accept) or "Exception" (reject/backordered).

### 6. Implement invoice flip and 3-way match

The supplier submits an invoice via the SRM portal (or cXML InvoiceDetailRequest). The SRM platform validates it against the PO, then flips it to the ERP for 3-way matching (PO + receipt + invoice). [src2, src7]

```python
# Python: Coupa invoice flip — fetch approved invoices and push to ERP
# Input:  Coupa API credentials, ERP API endpoint
# Output: Invoices created in ERP AP module

import requests
import time

def flip_coupa_invoices_to_erp(coupa_url: str, coupa_token: str,
                                erp_url: str, erp_token: str):
    """Fetch Coupa-approved invoices and create in ERP for 3-way match."""
    headers = {
        "Authorization": f"Bearer {coupa_token}",
        "Accept": "application/json"
    }

    # Fetch invoices approved in Coupa, not yet synced to ERP
    offset = 0
    while True:
        resp = requests.get(
            f"{coupa_url}/api/invoices",
            headers=headers,
            params={
                "status": "approved",
                "exported": "false",
                "limit": 50,
                "offset": offset
            }
        )
        if resp.status_code == 429:
            retry_after = int(resp.headers.get('Retry-After', 60))
            time.sleep(retry_after)
            continue
        resp.raise_for_status()

        invoices = resp.json()
        if not invoices:
            break

        for inv in invoices:
            erp_invoice = {
                "vendor_id": inv["supplier"]["number"],
                "invoice_number": inv["invoice-number"],
                "invoice_date": inv["invoice-date"],
                "po_number": inv["order-header-num"],
                "currency": inv["currency"]["code"],
                "total_amount": float(inv["total"]),
                "lines": [{
                    "po_line": line["order-line-num"],
                    "quantity": float(line["quantity"]),
                    "unit_price": float(line["price"]),
                    "amount": float(line["total"]),
                    "description": line["description"]
                } for line in inv["invoice-lines"]]
            }

            # Push to ERP AP module
            erp_resp = requests.post(
                f"{erp_url}/api/ap-invoices",
                headers={"Authorization": f"Bearer {erp_token}",
                         "Content-Type": "application/json"},
                json=erp_invoice
            )
            erp_resp.raise_for_status()

            # Mark as exported in Coupa
            requests.put(
                f"{coupa_url}/api/invoices/{inv['id']}",
                headers={**headers, "Content-Type": "application/json"},
                json={"exported": True}
            )

        offset += 50
```

**Verify**: Invoice appears in ERP AP module. 3-way match (PO amount + receipt quantity + invoice amount) passes within configured tolerance.

## Data Mapping

### Vendor Master Sync (SRM ↔ ERP)

| SRM Field | ERP Field (SAP) | ERP Field (Oracle) | Type | Transform | Gotcha |
|---|---|---|---|---|---|
| Supplier Name | LFA1-NAME1 | HZ_PARTIES.PARTY_NAME | String | Direct | SAP max 35 chars; Oracle max 360 chars |
| Tax ID | LFA1-STCEG | ZX_REGISTRATIONS.REGISTRATION_NUMBER | String | Strip formatting | Validate format per country (VAT, EIN, etc.) |
| Bank Account | LFBK-BANKN | IBY_EXT_BANK_ACCOUNTS.BANK_ACCOUNT_NUM | String | Encrypted at rest | Never transmit in cXML — use separate secure channel |
| Payment Terms | LFB1-ZTERM | AP_TERMS_TL.NAME | Code/String | Map code tables | SRM and ERP payment term codes rarely match — build mapping table |
| Address | LFA1-STRAS/ORT01/PSTLZ | HZ_LOCATIONS.ADDRESS1/CITY/POSTAL_CODE | String | Split/merge fields | SAP has one street field; Oracle has 4 address lines |
| Currency | LFB1-WAERS | FND_CURRENCIES.CURRENCY_CODE | ISO 4217 | Direct | Validate against ERP's enabled currency list |
| Supplier Category | LFA1-KTOKK | POS_SUPPLIER_CLASSIFICATIONS | Code | Map to ERP category set | SRM categories are hierarchical; ERP may be flat |
| DUNS Number | LFA1-KRAUS | HZ_PARTIES.DUNS_NUMBER_C | String | Direct | Required for Ariba Network registration |

[src7, src8]

### cXML-to-ERP Document Mapping

| cXML Element | SAP IDoc Segment | Oracle REST Field | Notes |
|---|---|---|---|
| OrderRequest.orderID | E1BPMEPOHEADER-PO_NUMBER | PoHeaderId (auto-generated) | SAP requires 10-char PO number; pad or truncate |
| ItemOut.quantity | E1BPMEPOITEM-QUANTITY | PoLineId.Quantity | Decimal precision varies — cXML allows 4 decimals, SAP allows 3 |
| UnitPrice.Money | E1BPMEPOITEM-NET_PRICE | PoLineId.UnitPrice | Currency must match PO header currency |
| Classification@UNSPSC | E1BPMEPOITEM-MATL_GROUP | PoLineId.CategoryId | Map UNSPSC to ERP material group / category |
| ShipTo.PostalAddress | E1BPMEPOHEADER-SUPPL_PLNT (plant) | ShipToLocationId | SRM sends full address; ERP expects location ID — requires lookup table |
| InvoiceDetailRequest.invoiceID | RBKP-BELNR | ApInvoiceId | ERP generates its own invoice number — store cross-reference |

[src1, src5]

### Data Type Gotchas

- cXML Money elements use ISO 4217 currency codes but store amounts as strings — always parse to decimal, not float, to avoid rounding errors in financial documents. [src2]
- UNSPSC classification in cXML uses 8-digit codes; SAP material groups are typically 3-digit codes — you need a maintained mapping table that is specific to your organization. [src1]
- cXML timestamps are ISO 8601 with timezone; SAP IDocs use YYYYMMDD + HHMMSS in separate fields without timezone — always convert to UTC before writing to SAP. [src5]
- Quantity UOM codes differ: cXML uses ANSI X12 UOM (EA, BX, CS); SAP uses ISO UOM codes (PCE, BOX, CAS); Oracle uses both — build a bidirectional UOM mapping table. [src3]

## Error Handling & Failure Points

### Common Error Codes

| Code | Context | Meaning | Cause | Resolution |
|---|---|---|---|---|
| 401 | cXML Response | Unauthorized | SharedSecret mismatch or expired credentials | Re-exchange credentials with trading partner; verify ANID/NetworkId |
| 403 | cXML Response | Forbidden | Buyer-supplier relationship not enabled on network | Supplier must accept trading relationship invitation on SRM portal |
| 406 | cXML Response | Not Acceptable | Malformed cXML document | Validate against cXML DTD before sending; check character encoding (UTF-8 required) |
| 409 | Coupa REST | Conflict | Duplicate invoice number for same supplier | Implement idempotency — check for existing invoice before creating |
| 429 | Coupa REST | Rate limit exceeded | Too many API calls in window | Exponential backoff: wait `Retry-After` header seconds; batch requests |
| 450 | Ariba Network | Document validation failed | Line items don't match contract/catalog pricing | Compare PO line prices against active contract; update catalog if stale |
| 500 | SRM Platform | Internal server error | Platform-side issue | Retry 3x with exponential backoff; escalate to SRM vendor support after 3 failures |

[src1, src2, src4]

### Failure Points in Production

- **Punch-out session timeout**: User takes >30 min browsing supplier catalog. The ERP session expires, and the PunchOutOrderMessage POST fails silently. Fix: `Extend ERP session timeout for punch-out sessions; implement client-side keepalive pings every 5 minutes`. [src3]
- **Supplier not enabled on network**: PO cXML sent to Ariba Network but supplier has not completed registration. Document queues for 72h then fails. Fix: `Build a supplier enablement check into PO creation workflow — query Ariba API for supplier status before transmitting PO`. [src8]
- **3-way match false mismatch**: Invoice arrives before goods receipt is posted in ERP. 3-way match fails because receipt quantity = 0. Fix: `Implement a configurable match-hold window (48-72h) that retries matching after receipt posting; or use 2-way match for service POs`. [src7]
- **cXML character encoding corruption**: Special characters in supplier names or descriptions (accents, CJK) cause XML parsing failures. Fix: `Enforce UTF-8 encoding in all cXML documents; strip or entity-encode non-UTF-8 characters at the middleware layer`. [src5]
- **Duplicate PO transmission**: Network latency causes ERP to retry PO send, creating duplicate POs on the SRM platform. Fix: `Use cXML payloadID as an idempotency key; SRM platforms de-duplicate on payloadID`. [src1]
- **Invoice flip currency mismatch**: Invoice submitted in supplier's currency but PO is in buyer's currency. SRM platform converts, but ERP expects PO currency. Fix: `Always flip invoices in PO currency; handle FX conversion in the SRM platform or middleware, not in the ERP AP module`. [src2]

## Anti-Patterns

### Wrong: Polling SRM platform for new POs/invoices on a timer

```python
# BAD — polling every 5 minutes wastes API quota and misses real-time documents
while True:
    invoices = coupa_api.get("/invoices", params={"status": "new"})
    for inv in invoices:
        process(inv)
    time.sleep(300)  # 5-minute polling interval
```

### Correct: Use webhooks or event-driven notifications

```python
# GOOD — Coupa/Ariba push documents to your endpoint in real-time
@app.route("/webhooks/coupa/invoice", methods=["POST"])
def handle_coupa_invoice_webhook(request):
    """Coupa pushes new invoice events to this endpoint."""
    payload = request.json
    invoice_id = payload["id"]

    # Fetch full invoice details (webhook payload is summary only)
    invoice = coupa_api.get(f"/invoices/{invoice_id}")
    process_invoice(invoice)
    return {"status": "received"}, 200
```

### Wrong: Syncing entire vendor master nightly as a full extract

```python
# BAD — full extract of 50K suppliers every night; wastes bandwidth, misses intraday changes
def nightly_vendor_sync():
    all_suppliers = srm_api.get("/suppliers", params={"limit": 50000})
    for s in all_suppliers:
        erp_api.upsert_vendor(s)
```

### Correct: Use delta/change-based sync with timestamps

```python
# GOOD — only sync suppliers modified since last sync
def delta_vendor_sync(last_sync_timestamp: str):
    """Fetch only changed suppliers since last successful sync."""
    offset = 0
    while True:
        suppliers = srm_api.get("/suppliers", params={
            "updated-at[gt]": last_sync_timestamp,
            "limit": 50,
            "offset": offset
        })
        if not suppliers:
            break
        for s in suppliers:
            erp_api.upsert_vendor(map_supplier_to_vendor(s))
        offset += 50
    save_last_sync_timestamp(datetime.utcnow().isoformat())
```

### Wrong: Hardcoding cXML SharedSecrets in source code

```xml
<!-- BAD — credentials in version control -->
<SharedSecret>MySecretPassword123</SharedSecret>
```

### Correct: Use environment variables or secrets manager

```python
# GOOD — credentials from secrets manager
import os
shared_secret = os.environ.get("ARIBA_SHARED_SECRET")
# Or: aws secretsmanager / Azure Key Vault / HashiCorp Vault
```

## Common Pitfalls

- **Ignoring SRM platform sandbox differences**: Ariba and Coupa sandbox environments have different URLs, credentials, and supplier data than production. Integration tested in sandbox may fail in production due to different supplier enablement status. Fix: `Maintain separate config profiles per environment; re-test supplier enablement in production after go-live`. [src8]
- **Not mapping UOM codes bidirectionally**: cXML, SAP, and Oracle all use different UOM code sets. A "box" might be BX (cXML), BOX (SAP), or Box (Oracle). Fix: `Build and maintain a UOM mapping table; validate UOM before sending any cXML document`. [src3]
- **Assuming all suppliers support cXML**: Many small suppliers only support email/PDF POs or basic portal entry. Sending cXML to a non-enabled supplier causes silent failure. Fix: `Store integration capability per supplier in vendor master; route POs through appropriate channel (cXML, email, EDI, portal)`. [src7]
- **Skipping cXML DTD validation**: Sending malformed cXML causes 406 rejections that are hard to debug. Fix: `Validate every outbound cXML document against the official DTD (cxml.org) before transmission`. [src6]
- **Not handling partial order confirmations**: Supplier confirms 40 of 50 units. Integration marks entire PO as confirmed. Fix: `Parse ConfirmationItem-level quantities; update ERP PO line-by-line; flag partial confirmations for buyer review`. [src1]
- **Neglecting punch-out catalog price vs. PO price drift**: Catalog prices update in the SRM portal but the ERP-side catalog cache is stale. Users see one price in punch-out, get a different price on the PO. Fix: `Implement real-time price validation at PO creation; or set punch-out cart prices as binding (contract-backed)`. [src2]

## Diagnostic Commands

```bash
# Test cXML connectivity to Ariba Network (ProfileRequest — lightweight health check)
curl -X POST https://service.ariba.com/service/transaction/cxml.asp \
  -H "Content-Type: text/xml" \
  -d '<?xml version="1.0"?>
<!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.050/cXML.dtd">
<cXML payloadID="healthcheck@buyer.com" timestamp="'$(date -u +%Y-%m-%dT%H:%M:%S+00:00)'">
  <Header>
    <From><Credential domain="NetworkId"><Identity>'$ARIBA_BUYER_ANID'</Identity></Credential></From>
    <To><Credential domain="NetworkId"><Identity>'$ARIBA_SUPPLIER_ANID'</Identity></Credential></To>
    <Sender><Credential domain="NetworkId"><Identity>'$ARIBA_BUYER_ANID'</Identity><SharedSecret>'$ARIBA_SHARED_SECRET'</SharedSecret></Credential><UserAgent>Diagnostic/1.0</UserAgent></Sender>
  </Header>
  <Request><ProfileRequest/></Request>
</cXML>'

# Test Coupa API authentication (OAuth 2.0 token request)
curl -X POST "https://${COUPA_INSTANCE}.coupahost.com/oauth2/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=${COUPA_CLIENT_ID}&client_secret=${COUPA_CLIENT_SECRET}&scope=core.read"

# Check Coupa supplier integration status
curl -X GET "https://${COUPA_INSTANCE}.coupahost.com/api/suppliers?number=${SUPPLIER_NUMBER}" \
  -H "Authorization: Bearer ${COUPA_TOKEN}" \
  -H "Accept: application/json"

# Validate cXML document against DTD (local validation before sending)
xmllint --valid --dtdvalid cXML.dtd outbound_order.xml

# Check SAP CIG IDoc processing status (SAP BTP monitoring)
# Use SAP BTP cockpit → Integration Suite → Monitor → Message Processing Logs
# Filter by: Sender = SAP_ERP, Receiver = ARIBA_NETWORK, Status = FAILED

# Test Jaggaer API connectivity
curl -X GET "https://${JAGGAER_INSTANCE}.jaggaer.com/api/v1/suppliers?limit=1" \
  -H "Authorization: Bearer ${JAGGAER_TOKEN}" \
  -H "Accept: application/json"
```

## Version History & Compatibility

| Protocol/Platform | Version | Release Date | Status | Breaking Changes | Notes |
|---|---|---|---|---|---|
| cXML | 1.2.056 | 2025-06 | Current | None | Added PaymentRemittance enhancements |
| cXML | 1.2.050 | 2023-01 | Supported | None | Most widely deployed version |
| OCI | 5.0 | 2022-01 | Current | Added JSON support (alongside HTTP POST) | SAP-only; backward compatible with OCI 4.0 |
| OCI | 4.0 | 2015-01 | Supported | None | HTTP POST only; no JSON |
| SAP CIG | Renamed to Integration Suite | 2025-H1 | Current | New BTP deployment model | Existing CIG deployments auto-migrated |
| Coupa REST API | R35 | 2025-12 | Current | Token-based supplier portal access | New OAuth scope requirements |
| Coupa REST API | R34 | 2025-06 | Supported | None | — |
| Jaggaer REST API | 2024.2 | 2024-11 | Current | New supplier management endpoints | REST API still maturing |

[src2, src3, src5]

### Deprecation Policy

cXML is maintained by the cxml.org consortium; versions are additive and backward compatible — no version has ever been deprecated. SRM platforms (Ariba, Coupa, Jaggaer) deprecate API versions on individual release cycles, typically with 12-18 months notice. SAP CIG (now SAP Integration Suite) follows SAP BTP deprecation policy with minimum 12-month notice. [src5]

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| You have 50+ suppliers on Ariba, Coupa, or Jaggaer and need automated PO/invoice flow | Fewer than 10 suppliers — manual portal entry is simpler | Direct email/PDF PO workflow |
| You need real-time catalog pricing via punch-out | You have static catalogs that change quarterly | Hosted catalog upload (CSV/BMEcat) |
| You need automated 3-way match across procurement + ERP | You only need simple 2-way match (PO vs invoice) | business/erp-integration/invoice-to-pay-ap-automation/2026 |
| Suppliers are already registered on an SRM network | You need to build a custom supplier portal | Custom development with ERP APIs |
| You need supplier onboarding, qualification, and risk scoring | You only need vendor master data sync | business/erp-integration/master-data-management-erp/2026 |
| You are integrating SAP ERP with SAP Ariba | Non-SAP ERP with Ariba (CIG not available) | cXML direct or iPaaS middleware |

## Cross-System Comparison

| Capability | SAP Ariba | Coupa | Jaggaer ONE | Notes |
|---|---|---|---|---|
| Punch-out protocol | cXML + OCI | cXML only | cXML + OCI | OCI only relevant for SAP ERPs |
| PO transmission | cXML, EDI, email | cXML, email, portal | cXML, EDI, email, portal | Ariba Network has largest supplier base |
| Invoice methods | cXML, Ariba Network portal, EDI | cXML, CSV, email/PDF (InvoiceSmash AI), portal | cXML, portal, email | Coupa InvoiceSmash AI auto-OCRs PDF invoices |
| Supplier network size | 5.3M+ companies | 10M+ companies | 4M+ companies | Network size = supplier adoption ease |
| REST API maturity | Moderate (newer) | High (comprehensive) | Growing (newer REST surface) | Coupa REST API is most complete |
| ERP pre-built connectors | CIG for SAP (native) | iPaaS connectors (Boomi, MuleSoft) | iPaaS connectors | Ariba-SAP has deepest native integration |
| Free supplier portal | Yes (Ariba Network) | Yes (Coupa Supplier Portal) | Yes (basic) | Supplier cost varies by transaction volume |
| Contract management | Yes (Ariba Contracts) | Yes (CLM module) | Yes (Contracts+) | All three support contract-backed catalogs |
| Supplier risk scoring | Yes (Ariba Risk) | Yes (Coupa Risk Assess) | Yes (Risk Management) | Third-party data (D&B, Ecovadis) integrations |
| AI/ML features | Ariba Spot Buy, guided buying | Coupa Pay, InvoiceSmash AI | Jaggaer AI (agentic sourcing, 2025) | Rapidly evolving; verify current capabilities |

## Important Caveats

- SRM platform pricing and capabilities vary significantly by contract tier — features described here may require premium/enterprise licensing not included in base subscriptions.
- Supplier network sizes are self-reported by vendors and include inactive accounts — actual active supplier coverage varies by industry and geography.
- cXML is an open standard but each SRM platform adds proprietary extensions — documents that work on Ariba may require modification for Coupa or Jaggaer.
- SAP CIG (now SAP Integration Suite, managed gateway) is only available for SAP ERP backends — non-SAP ERPs must use cXML direct or iPaaS.
- Rate limits and API quotas are subject to change with each platform release — always verify current limits against the platform's developer documentation.
- This playbook covers the integration architecture and protocols — specific ERP-side configuration (transaction codes, data entities, OData endpoints) is covered in the individual ERP API capability cards.

## Related Units

- [Master Data Management for ERP](/business/erp-integration/master-data-management-erp/2026) — vendor master sync patterns (prerequisite)
- [Procure-to-Pay Integration](/business/erp-integration/procure-to-pay-integration/2026) — internal P2P flow including matching and payment
- [Invoice-to-Pay AP Automation](/business/erp-integration/invoice-to-pay-ap-automation/2026) — downstream invoice processing after SRM flip
- [SAP IDoc/EDI Integration](/business/erp-integration/sap-idoc-edi-integration/2026) — traditional EDI-based procurement without SRM portal
- [iPaaS Platform Comparison](/business/erp-integration/ipaas-platform-comparison/2026) — middleware selection for multi-platform SRM integration
