SK SKYVVA Documentation

12. Outbound Synchronous Interface: Salesforce Account to SAP CPI (Request/Response)

1. Overview

This document describes how to create an outbound Synchronous interface from Salesforce to SAP CPI that sends a flat Account record and receives a response back in the same transaction, using MessageType-less mapping throughout — no OpenAPI import, no Message Type tree on either interface. Unlike the sibling outbound Asynchronous tutorial's scenario (fire-and-forget, no response expected), this one needs:

image

Figure 1: Salesforce Account pushed synchronously to SAP CPI and the response routed back — end-to-end flow.

1.1 Business Context

Use this pattern when the calling Salesforce transaction needs CPI's response back before it can proceed — for example, SAP (or a system behind CPI) validates or enriches a single Account's data — a tax ID check, a credit status lookup, an assigned SAP customer number — and Salesforce needs that result immediately, before the record save completes, not asynchronously.

Keep the payload flat and minimal for this pattern. A synchronous call blocks the calling transaction until CPI answers, so it should carry only the fields the immediate decision actually needs — not a parent record bundled together with a full list of child records. If what you actually need is to keep Account and Contact data consistent between Salesforce and SAP, that's a data-synchronization concern, better served by asynchronous/batch patterns — outbound for pushing Salesforce-side changes, one of the inbound Bulk-mode tutorials for pulling SAP-side changes — than by a blocking synchronous call. Reach for this pattern specifically when a single record's validated/enriched result has to come back in-line, and use the outbound Asynchronous pattern (the sibling tutorial in this series) for anything where Salesforce only needs to notify a downstream system and doesn't need anything back in the same transaction.

1.2 Tutorial Scenario

This tutorial pushes one Account record Synchronously to SAP CPI as JSON and expects a response back in the same call, triggered via Apex (invokeCalloutV3, §4.1) so the flow can be verified end-to-end without waiting for a real business event.

It configures the Salesforce-side outbound adapter (Adapter__c.Type__c = 'SAP CPI'), where Salesforce is the caller. The separate SkyvvaSalesforce CPI adapter (installed inside the SAP CPI iFlow designer) is the opposite direction — see the earlier tutorials in this series covering that CPI-side adapter's Sender/Receiver channel setup instead.

Pre-requisites:


2. Salesforce Interface Development

2.1 Create the Integration and the Request Interface

Create a SKYVVA Outbound Interface under Integration in Salesforce (create the parent Integration record first if you don't already have one).

Configure the outbound Request interface:

FieldValue
NameAccount_INT_REQ_SFDC2SAP_Sync_OB
IntegrationYour Integration record
Source/Target NameAccount
StatusDeployed
Interface DirectionOutbound
Processing ModeSynchronous
Interface API VersionV3 — required for MessageType-less mapping
Response InterfaceAccount_INT_RES_SFDC2SAP_Sync_IB (create this next, §2.2, then come back and link it here)
Note: leave MetaData Provider/Repository/Source-Target Message Type blank — this interface is MessageType-less. Skip straight to §2.2 to create the Response interface, then §2.3.1 to map fields; no Message Type build step is needed for either interface.
image

Figure 2: New Interface form — the outbound Request interface.

2.2 Create the Response Interface

Back on the same Integration record's Interfaces related list, click New Interface again to create a second interface for the inbound Response:

FieldValue
NameAccount_INT_RES_SFDC2SAP_Sync_IB
IntegrationYour Integration record
Source/Target NameAccount
StatusDeployed
Interface DirectionInbound
Processing ModeSynchronous
Interface API VersionV3
External Mappingchecked
Request InterfaceAccount_INT_REQ_SFDC2SAP_Sync_OB
Note — MetaData Provider / Repository / Source-Target Message Type: leave these blank, same as the Request interface. Salesforce's response routing goes by Message Type, not Interface API Version — leaving Message Type blank keeps this response following the MessageType-less path this tutorial uses, regardless of the External Mapping setting.
image

Figure 3: New Interface form — the inbound Response interface.


image

Figure 4: New Interface form — the Response interface's External Mapping checkbox, checked.


Go back to the Request interface (§2.1) and set its Response Interface field to this record now that it exists.

image

Figure 5: Request interface — Response Interface field set, pointing to the Response interface.


The two interfaces now link to each other in both directions — the Response interface's own Request Interface field (set in §2.2) already points back the other way.

image

Figure 6: Response interface — Request Interface field pointing back to the Request interface.

2.3 Create the Custom Fields This Interface Needs

Two fields carry SAP's response back onto the Account record. AccountNumber is a standard field — nothing to create. skyvvasolutions__Credit_Status__c isn't: create it yourself as a new custom field on Account (any label; the API name is what matters).

With External Mapping checked (§2.2), the Response interface needs no explicit field-mapping step at all (§2.3.1) — AccountNumber/skyvvasolutions__Credit_Status__c resolve directly by matching field name, same as the outbound side. Note skyvvasolutions__Credit_Status__c is a field you create here — don't confuse it with skyvvasolutions__Credit_Check_Result__c, a different, similarly-named field the package ships that this tutorial doesn't use.

2.3.1 Map Account Fields (Request)

Open Open Mapping on the Request interface. On a MessageType-less V3 interface, the Mapping Tool's Source tree mirrors Account all the way down. Drag Name/BillingCountry/skyvvasolutions__Tax_ID__c from the Source tree onto the matching, identically-named Target fields. Map each field and save.

image

Figure 7: Mapping Tool — field mapping on the Request interface, sourced from the Account.

No mapping step for the Response interface. With External Mapping checked (§2.2), the incoming AccountNumber/skyvvasolutions__Credit_Status__c fields resolve directly by name — there's nothing to drag-and-drop in the Mapping Tool for this interface.

2.4 Create the Skyvva SAP BTP Integration Suite Adapter

Navigate to Integration → Details → SAP Control Board → Adapter, click New, and configure it exactly as documented in the outbound Asynchronous tutorial's §2.4 (full field-by-field reference) — the adapter configuration itself doesn't differ between the asynchronous and synchronous scenarios. For this tutorial:

FieldValue for this tutorial
Adapter NameAccount_ADAPTER_Sync
Type"SAP BTP Integration Suite" in the dropdown (stores SAP CPI)
DirectionOutbound
Authentication TypeBasic (or another value — see the outbound Asynchronous tutorial's §2.4 for all five options)
ProtocolHTTP
OperationPOST
Request Formatapplication/json
Response Formatapplication/json
API Service Endpoint URLyour CPI iFlow's endpoint URL
Salesforce Id HandlingReturn Salesforce Id into the response
Setting Salesforce Id Handling to Return Salesforce Id into the response includes the Account's own Salesforce Id in what comes back, so the response can be matched to the right record.

Why JSON, not this adapter's own default (application/xml): application/xml is this adapter type's coded default, but Salesforce as a REST-style caller typically speaks JSON. Picking JSON here keeps the outbound payload in that native format; CPI bridges it to XML internally via its standard JSON→XML converter step (§3), then maps the response straight back to JSON without a second conversion step.


image

Figure 8: New Adapter dialog — Account_ADAPTER_Sync.


Save the adapter, then add it to the Request interface's Outbound Setup.

image

Figure 9: Adapter linked to the Request interface's Outbound Setup.

3. SAP CPI Development

This section describes generic CPI palette steps (HTTPS sender, schema import, JSON→XML, XSLT mapping), not anything specific to the SkyvvaSalesforce adapter — treat it as a starting point and confirm against your own CPI tenant's current palette.

Log on to the CPI tenant, navigate to Design → Packages → Artifacts → Create new integration flow.

  1. Create the sender HTTPS communication channel and provide the connection parameters.
  2. Export an OpenAPI schema from the Response interface for Message Mapping's Target side — needed since there's no hand-authored OpenAPI spec to reuse now that the interface is MessageType-less. On the Response interface's record page, click Generate MetaData (header button) and set Format = OpenAPI 3.0. API must be set to V4/Integrate — this is required, not just a default; picking a different API value here generates the wrong schema shape for a MessageType-less interface. Then download the file. (No export is needed from the Request interface — see the Message Mapping step below for why.)

Note: with no Message Type, the exported schema is generated from the full Account object describe, not a curated field list — it will contain every field on Account, not just AccountNumber/skyvvasolutions__Credit_Status__c. You'll pick the specific elements you actually want when building the Message Mapping step below — the extra fields in the file are just noise.


  1. Build the flow:

The JSON→XML conversion near the start isn't a workaround — it's CPI's standard bridge pattern for a REST-style caller (Salesforce) sending a request to a platform (CPI/SAP) that processes internally as XML.

Message Mapping's Source isn't the Request interface's schema. Message Mapping sits after Call SAP - Tax ID Validation (§3 step 4) in the flow, so the payload actually in the message body at that point is SAP's own response — not a restatement of the Name/BillingCountry/skyvvasolutions__Tax_ID__c fields Salesforce originally sent. This step exists specifically because SAP's response uses its own field names, not Salesforce's — without this mapping, whatever SAP calls its assigned customer number and credit result would never line up with AccountNumber/skyvvasolutions__Credit_Status__c on the way back.

Open the Message Mapping step's editor (double-click it on the canvas): for Source, the preferred approach is Select → Add, uploading the OpenAPI (or WSDL/XSD) file your SAP backend team provides for this response — most external systems worth integrating with document their own response contract, and importing it is both more accurate and easier to keep in sync than reconstructing it from one sample payload. Only fall back to **Select → Define from Example** (a real sample response payload) if the backend genuinely has no published schema to hand you. A worked example of this backend-provided file — tools/cpi-xsd/tutorial13-sap-backend-response.openapi.json — documents a representative response shape:

		{
     "ValidationResponse": {
       "CustomerNumber": "000010971",
       "CreditCheckResult": "APPROVED"
     	}
   	}

This response body is flat — no wrapping node — so the Source side of the Message Mapping editor will show CustomerNumber/CreditCheckResult directly, not nested under any parent element. That's expected, not a sign anything imported incorrectly.

Note SAP's own field names (CustomerNumber, CreditCheckResult) are not the same as Salesforce's (AccountNumber, skyvvasolutions__Credit_Status__c) — this mismatch is exactly why the mapping step is needed, not optional. For Target (the shape sent back to Salesforce), click Select → Add, upload the Response interface's exported OpenAPI file (step 2), and pick AccountNumber/skyvvasolutions__Credit_Status__c, under its Account node. Then draw the actual field lines: CustomerNumber → Account/AccountNumber, CreditCheckResult → Account/skyvvasolutions__Credit_Status__c.

image

Figure 10: CPI Message Mapping — Target structure built from the Response interface's exported OpenAPI schema; Source reflects SAP's actual response shape.


  1. Configure the Call SAP - Tax ID Validation step (the Request-Reply added on the connecting arrow between XSLT Mapping and Message Mapping — hover the arrow, click the + that appears, choose Request-Reply, then rename it via its General tab), then wire its output side to a Receiver pool with an HTTPS adapter:

Connection tab:

FieldValue
AddressYour SAP backend's endpoint
Proxy TypeInternet, or On-Premise via Cloud Connector for an on-prem SAP backend
MethodPOST
AuthenticationWhatever your real backend requires (Basic, OAuth2 Client Credentials, Client Certificate, ...) — None if calling a plain testing mock. Client Certificate needs a Private Key Alias filled in — leaving it blank while that mode is selected will fail.
Timeout60000 ms is a reasonable default
StreamingLeave unchecked — this response is small

Retry tab:

FieldValueWhy
Attach Error Details on FailurecheckedAttaches the backend's actual error response to the exception — visible in Message Processing Log, useful for diagnosing failures
Retry on Exceptionunchecked while testing; consider enabling against a real production backendA validation failure (e.g. malformed Tax ID) is deterministic — retrying won't change the result. Transient network failures against a real backend are a different story.
Retry on Error ResponseuncheckedSame reasoning — a 4xx rejection isn't going to succeed on retry

Add a Content Modifier named Set SAP Request Content-Type immediately before this step, setting Content-Type: application/json — needed for the request body to be parsed correctly by most backends.

image

Figure 11: SAP CPI iFlow — completed flow overview.


Getting a real synchronous response back doesn't need a dedicated CPI setting — it's a consequence of how the flow is built:

  1. Keep the whole flow inline (no JMS queue or separate Process Direct hand-off) so the caller's connection stays open until the End Event, and receives whatever is in the message body at that point.
  2. Make sure the last step before the End Event builds the response shape as JSON, matching the fields mapped on the Response interface (§2.3.1) and Response Format = application/json (§2.4).
  3. Set Content-Type: application/json via a Content Modifier named Set Response Content-Type right before the End Event.

image

Figure 12: Set Response Content-Type Content Modifier, setting the response Content-Type header before the End Event.


  1. HTTP status matters too. CPI returns 200 OK by default when the flow completes without an exception, which is fine for the happy path. To signal a validation failure differently, set a different code via the CamelHttpResponseCode header on a Content Modifier — optional for this tutorial.

4. Testing

4.1 Push Data from Salesforce to CPI Using Apex

Use the same customer as the outbound Asynchronous tutorial's §4.1 — this tutorial demonstrates the synchronous counterpart: instead of just notifying SAP the customer exists, this call needs SAP's validated Tax ID check and assigned customer number back before Salesforce proceeds.

FieldExample valueRole in this call
NameNordwind Fahrzeugteile GmbHSent — identifies the customer to SAP
BillingCountryDESent — needed for the Tax ID check
skyvvasolutions__Tax_ID__cDE813495681Sent — custom field, created in §2.3; API name must be exactly skyvvasolutions__Tax_ID__c for the Mapping Tool to line it up with the JSON key of the same name. The VAT/Tax ID SAP validates.
AccountNumber(blank until the response comes back)Returned — standard Salesforce field; the Response interface writes SAP's assigned customer number here.
skyvvasolutions__Credit_Status__c(blank until the response comes back)Returned — custom field, created in §2.3 (not the package's skyvvasolutions__Credit_Check_Result__c — that field isn't used in this MessageType-less version). No mapping step needed (§2.3.1) — resolves by matching field name, since the Response interface uses External Mapping (§2.2). SAP's credit-check result.

Request JSON sent to CPI, reflecting the fields mapped onto the Request interface's Account node in the Mapping Tool (§2.3.1):

{
  "Account": {
    "Name": "Nordwind Fahrzeugteile GmbH",
    "BillingCountry": "DE",
    "skyvvasolutions__Tax_ID__c": "DE813495681"
  }
}

Response JSON CPI returns, matching the fields mapped on the Response interface (§2.3.1):

{
  "Account": {
    "AccountNumber": "000010971",
    "skyvvasolutions__Credit_Status__c": "Approved"
  }
}

Ensure at least one Account exists in Salesforce, matching the shape above.

image

Figure 13: Salesforce Account record used as test data, before the synchronous call.


Navigate to Developer Console → Debug → Open Execute Anonymous Window and run:

//Account_INT_REQ_SFDC2SAP_Sync_OB --Interface
skyvvasolutions.CallOutControl c = new skyvvasolutions.CallOutControl();
c.returnJSONComplete=true;
c.actionDoIntegrate=true;
c.isCreateMessage=true;
String[] ids= new String[]{'0019K00001tyyd9QAA'}; //Id SObject
List<skyvvasolutions.CalloutResponse> result = skyvvasolutions.Iservices.invokeCalloutV3('SAP CPI Integration','Account_INT_REQ_SFDC2SAP_Sync_OB',ids,'SYNC',c);

Click Execute to push the data, then monitor the message in both Salesforce and CPI.

image

Figure 14: Running the Apex script in the Execute Anonymous window.


Once the synchronous call returns, reopen the same Account record: AccountNumber and skyvvasolutions__Credit_Status__c — both blank in Figure 13 — are now populated from SAP's response, written by the Response interface's mapping (§2.3.1).

image

Figure 15: Salesforce Account record after the synchronous call — AccountNumber/skyvvasolutions__Credit_Status__c populated by the returned response.

4.2 Salesforce Message Monitor

Navigate to Message Monitoring and search using the interface/integration details. The outbound message should show a green flag (success) status — and because this is a Synchronous call with a Response Interface configured, you should also see an inbound response message cross-linked to it.

image

Figure 16: Salesforce Message Monitoring — outbound Request message cross-linked to the inbound Response message.

4.3 CPI Monitoring

Navigate to Message Monitoring in CPI to find the corresponding message with its full log, confirming the Account data was received and a response was returned.

image image

Figure 17: SAP CPI Message Monitoring — request received and response returned.

Summary

ComponentConfiguration
Request InterfaceOutbound, Synchronous, Interface API Version = V3, MessageType-less
Response InterfaceInbound, Synchronous, Interface API Version = V3, MessageType-less, External Mapping — see §1's warning on the response-processing caveat
Custom fieldsskyvvasolutions__Tax_ID__c (Request) and skyvvasolutions__Credit_Status__c (Response) — both resolve by matching field name against the JSON key; no Message Type or explicit Mapping Tool step needed for either (§2.3, §2.3.1).
Schema for CPIResponse interface's schema exported via Generate MetaData (§3 step 2) for Message Mapping's Target; Source is SAP's own response shape — imported from the backend's published OpenAPI/WSDL/XSD file if they provide one (preferred), or Define from Example otherwise — never from Skyvva's own schema
SAP BTP Integration Suite AdapterOutbound, Basic auth, HTTP, POST, JSON (Request/Response Format = application/json; CPI bridges the outbound request to XML internally via §3's JSON→XML converter step — the response comes back as JSON directly, no converter needed on that side)

This is the response-carrying counterpart to the sibling outbound Asynchronous tutorial — the adapter configuration is the same between the two; what differs is the Request/Response interface pairing that Processing Mode = Synchronous requires. Keep the record flat and minimal — just the fields the immediate decision needs. If your use case needs to keep Account and Contact data consistent across systems instead, that's what the asynchronous/batch patterns elsewhere in this series are for.

Open this article in the interactive viewer →