7. How to create an inbound interface using Skyvva Batch mode with SkyvvaSalesforce Adapter
Overview
This document explains how to create a SKYVVA Inbound Interface in Salesforce that processes incoming record sets through Skyvva Batch mode — the SkyvvaSalesforce receiver channel's Mode = Skyvva Batch setting, which groups incoming records into packages before sending each one as a direct REST call to Salesforce.
Note: don't confuse this with the olderintegrateBatchREST API documented in [Tutorial 4](4-how-to-create-an-inbound- nterface-using-integratebatch--with-skyvvasalesforce-adapter) (Skyvva API Version = V2, a separate/integrateBatchendpoint with abatchmodeJSON flag).This tutorial covers the newer V3 mechanism — the same single/V3/Integrateendpoint and receiver-channelModedropdown used by Skyvva Bulk mode and Auto-Switch mode, just withMode = Skyvva Batchselected directly instead ofSkyvva Bulk/Auto-Switch. Both mechanisms end up in the same Batch Control Board on the Salesforce side, but the underlying code path, config fields, and defaults are entirely different — treat them as two unrelated features that happen to share the word batch."
It covers the following steps:
- Create and configure a SKYVVA Inbound Interface in Salesforce, with the Batch engine and package-size fields set for Skyvva Batch processing.
- Create an integration flow in SAP CPI.
- Configure the HTTPS sender channel.
- Configure the SKYVVA Salesforce receiver channel with
Skyvva API Version = V3andMode = Skyvva Batch. - Deploy the integration flow.
- Send a test request from Postman through SAP CPI.
- Monitor the message in SAP CPI.
- Process and verify the batch in Salesforce.
| Item | Value |
|---|---|
| Salesforce Object | Account / Contact (nested) |
| Message Source | Postman |
| Middleware | SAP CPI |
| SKYVVA API Version | V3 |
| Mode | Skyvva Batch |
| Processing Mode | Asynchronous |
| Batch Mode (Interface) | Checked |
| Package Size (Interface) | Package_Size__c (Transfer Package Size) = 15 — see §1.3 |
Context Before You Start
In short: Skyvva Batch mode groups incoming records into packages — sized by Package_Size__c (Transfer Package Size — see §1.3) — before sending each package as its own direct REST call to Salesforce. It chunks records into packages rather than sending everything as one call. This is a materially different mechanism from Skyvva Bulk mode: Batch mode never builds a file/attachment, never touches the Salesforce Bulk API, and each package becomes one direct REST call rather than one zipped ContentVersion upload.
Reasons to pick this path:
- The source system sends multiple records per call and you want them grouped into fewer, larger Apex transactions instead of one call per record — without the extra machinery (baskets, file attachments, background Bulk API jobs) that Skyvva Bulk mode brings.
- You want a middle ground between Normal/Asynchronous (no chunking at all) and Skyvva Bulk (file-based, Salesforce-Bulk-API-backed) — Batch mode chunks records but stays on the plain direct-Apex-call path the whole time.
- Moderate record volumes where full Bulk-mode machinery (baskets, attachments, background jobs) is more than you need, but sending every record as its own individual call would be wasteful.
- Hierarchical (parent-child) payloads too — this tutorial uses the same
Account-with-nested-Contactexample as the Bulk and Auto-Switch tutorials, since External Mapping and the Hierarchical Mapping Tool are V3-interface-level features, independent of whichModethe receiver channel uses.
Mode = Skyvva Batch), deploy, send a test payload from Postman, then confirm the resulting basket in the Batch Control Board and verify the records landed in Salesforce.
POSTMAN
↓
SAP CPI (HTTPS Sender → SkyvvaSalesforce Receiver, Mode = Skyvva Batch)
↓
SKYVVA Inbound Interface (Batch_Mode__c = true)
↓
Package (sized at Package_Size__c — §1.3)
↓
Salesforce Account / Contact
Figure 1: End-to-end message flow using Skyvva Batch mode.
1. Salesforce Interface Development
1.1 Create the Interface
Create a SKYVVA Inbound Interface under Integration in Salesforce (create the parent Integration record first if you don't already have one).
For this example, create the interface AccountContactSkyvvaBatch_IN. Leave the Message Type field blank. For a V3 Inbound interface, leaving Message Type unset is what triggers Hierarchical Mapping — there is no MetaData Provider/Repository/Message Type hierarchy to build first; the Mapping Tool derives the parent/child tree directly from Salesforce's own schema instead.
Configure the interface:
| Setting | Value |
|---|---|
| Interface Name | AccountContactSkyvvaBatch_IN |
| Integration | Your SAP CPI Integration App record |
| Source/Target Name | Account |
| Status | Deployed |
| Interface Direction | Inbound |
| Processing Mode | Asynchronous |
| Operation Type | Upsert |
| Message Type | (leave blank) |
| External Mapping | Enabled |
Figure 2: SKYVVA Inbound Interface AccountContactSkyvvaBatch_IN, no Message Type linked.
This is the main interface's own Inbound Setup section — with
External Mapping enabled, set Salesforce External ID = skyvvasolutions__ERP_DEBTOR_ID__c, the Account-level external key used to match/upsert Account records:
Figure 3: Main interface AccountContactSkyvvaBatch_IN — Inbound Setup, External Mapping enabled with Salesforce External ID skyvvasolutions__ERP_DEBTOR_ID__c (Account).
1.2 Map Account → Contact in the Hierarchical Mapping Tool
Open the interface's Mapping Tool (Interface detail page → Open Mapping). Because Message Type is blank on a V3 Inbound interface, the Source tree is built live from the Account object's own schema rather than from a predefined Message Type — including its child relationships. Expand the tree down to the Contact(AccountId) child-relationship node to reach it.
With External Mapping enabled on the interface (§1.1), field-level mapping is not needed — External Mapping auto-maps fields by name on its own. All this step has to do is drag the two relationship nodes, top-down, to generate the chained sub-interface:
- Drag the
Accountroot node onto the targetAccountroot first. This is required, not optional — the target tree doesn't display aContact(AccountId)node at all untilAccountitself has been mapped. Expanding the targetAccountnode beforehand shows only Account's other child relationship nodes (no individual fields are ever listed here — with External Mapping enabled, the tree doesn't expose fields for manual dragging at all), neverContact(AccountId), so there is nothing to drag the child relationship onto until the root mapping is done. - Expand
Contact(AccountId)and drag it onto the targetContact(AccountId)node. No individual field needs to be dragged in either step — this is a node-to-node mapping, not a field-to-field one.
Important — this step is not optional and cannot be replaced by External Mapping alone. Dragging the Contact(AccountId) node auto-creates a chained sub-interface behind the scenes (internal, engine-managed — you don't create or configure it yourself), and that's the actual mechanism that makes the Account+Contact hierarchy work at runtime. External Mapping only flat-maps fields on an interface that already exists; it doesn't create this chained structure or walk into child relationships on its own. Skip this step, and posting nested Contact data will not produce Contact records, no matter how the payload is shaped.
Figure 4: Hierarchical Mapping Tool — Account → Contact(AccountId) node mapping, External Mapping handles field-level mapping.
Save the mapping. Doing so auto-generates the chained sub-interface for the child
Contact object mentioned in the note above. That sub-interface has its own, separate Inbound Setup, with its own External Mapping keyed on the Contact-level external ID — skyvvasolutions__ERP_CONTACT_ID__c, not the Account-level ERP_DEBTOR_ID__c used on the main interface (§1.1). Don't confuse the two: they identify different objects, and the sub-interface's External Mapping has to be checked here independently — it is not inherited from the main interface just because External Mapping is enabled there.
Figure 5: Auto-generated sub-interface (Contact) — Inbound Setup, External Mapping enabled with Salesforce External ID skyvvasolutions__ERP_CONTACT_ID__c (Contact).
1.3 Configure the Batch Engine
Set the following two fields on the interface. Note that they live in two different sections of the page — Package_Size__c is up in the general Information section, not in Batch Setting where you might expect it:
| Field | Value | Why it matters |
|---|---|---|
Batch_Mode__c (Batch Mode) — Batch Setting section | Checked | Marks the interface as batch-capable. BatchControlBoardLightningController's own queries filter interfaces by Batch_Mode__c = true OR Use_Auto_Switch_Mode__c = true — without this checked and saved, the interface won't surface in the Batch Control Board even though CPI-driven calls will still process correctly (see the note below). |
Package_Size__c (Transfer Package Size) — Information section | 15 | The number of root records (Account, not counting nested Contact children) grouped into each package/basket. For a batch triggered from SAP CPI, this is the field that determines the package size — not Batch_Package_Size__c ("Batch Package Size") in the Batch Setting section, even though that field's name and location look like the obvious fit; Batch_Package_Size__c has no effect on this or any other processing mode, whatever value it's set to. Leave Batch_Package_Size__c and Number_of_Records_Per_Batch__c blank for this example. |
Package_Size__c is left blank, the package size falls back in order to Number_of_Records_Per_Batch__c (Processing Package Size) on the interface, then the parent Interface Group's own Number_of_Records_Per_Batch__c, then the Integration's Packet__c, then a default of 20 if all of those are blank too. Whichever of these is the first one populated decides the package size on its own — the fields below it in this order are not read at all for that call, so don't expect a blend of several of them at once.
Important: when this interface is driven via a CPI channel withMode = Skyvva Batch(as this tutorial sets up), the adapter overridesBatch_Mode__cin memory at request time to match the channel'sModesetting, regardless of what's stored on the record — so the CPI-driven call itself works whether or notBatch_Mode__cis checked on the record. But the Batch Control Board's own visibility filter reads the persisted record field, not the in-memory override — so you still needBatch_Mode__cchecked and saved on the interface for it to show up there after processing. This is the same relationship Skyvva Bulk mode has withisBULKAPI__cand the Bulk Control Board.
Figure 6: Interface's Batch Setting section — Batch Mode checked, Batch Package Size left blank(Transfer Package Size is set separately, in the Information section — see Figure 2).
After completing the configuration and mapping in Skyvva, save the interface.
2. SAP CPI Development
2.1 Create the Integration Flow
Create the package in SAP CPI under Design and add the integration flow.
Example:
| Item | Example |
|---|---|
| Integration Package | Skyvva Salesforce Adapter Testing |
| Integration Flow | AccountContact_Skyvva_Batch |
Figure 7: Integration flow for the Skyvva Batch mode example.
Important: the Message Mapping step may show a warning icon. Hovering it reveals: "Http Sender Component may not pass XML or JSON message to Message Mapping. Message Mapping supports XML or JSON input only." This is CPI's design-time validator flagging that it can't statically prove the HTTPS Sender's output is XML/JSON — the standard HTTPS Sender adapter has no fixed content-type contract, so CPI can't guarantee it at design time. It's not about incomplete field mapping, and it doesn't block deployment: this exact flow deploys and runs successfully despite it. Safe to leave as-is as long as callers actually send XML/JSON matching Request Format, as this tutorial's Postman example does.
Where the target schema comes from: export it via the Interface record's Generate MetaData button — Format = XSD Schema, API = V3/Integrate (Skyvva Batch is just a processing tier of the same Integrate endpoint, not a separate schema). Then, inside the Message Mapping step's own editor (double-click it on the iFlow canvas), go to the Target panel → Select → Add → upload the downloaded .xsd → pick its root element as the Target Message Type. The file is stored as a resource on this specific integration flow, not somewhere interface/adapter-level or CPI-wide — any other iFlow needing it has to import its own copy.
Note: this interface uses External Mapping withMessage Typeleft blank, so the exported schema comes from a live object describe rather than a curated tree — confirm it reflects the nestedAccount→Contactstructure before relying on it.
2.2 Configure the HTTPS Sender Channel
Select the standard SAP HTTPS sender adapter.
General tab: Direction Sender, Adapter Type HTTPS, Transport Protocol HTTPS, Message Protocol None — fixed values, identical in every tutorial that uses this sender.
Connection tab:
| Field | Example value |
|---|---|
| Address | /skyvva/AccountContactIntegrateSkyvvaBatchV3 |
| Authorization | User Role |
| User Role | ESBMessaging.send |
| CSRF Protected | Unchecked |
Important: The configured User Role must already exist and be assigned to the CPI user/credential that Postman authenticates as, or the sender rejects the request with 403 Forbidden.
Figure 8: HTTPS sender channel — Connection tab.
2.3 Configure the SkyvvaSalesforce Receiver Channel
Select SkyvvaSalesforce as the receiver adapter. The receiver channel has three tabs: General, Connection, Skyvva.
General tab: Direction Receiver, Adapter Type SkyvvaSalesforce, Transport Protocol https, Message Protocol skyvva — fixed values, identical for every SkyvvaSalesforce receiver channel.
2.3.1 Connection Tab
| Field | Example value |
|---|---|
| Authentication Type | OAuth2 |
| OAuth2 Flow | Username-Password Credential (or Client Credential) |
| Login Url | https://test.salesforce.com |
| User Credential | Your CPI Security Material alias for the Salesforce user (shown only for the Username-Password flow) |
| Client Credential | Your CPI OAuth2 Client Credentials artifact (required for either flow) |
Note: There is no separate "Client Id"/"Client Secret" pair on the current adapter — both are held inside the single Client Credential OAuth2 artifact deployed in the CPI keystore. For the full field reference see 1. SKYVVA CPI Salesforce Receiver Adapter in SAP Cloud Integration.md §3.
2.3.2 Skyvva Tab — Request Settings
| Field | Value |
|---|---|
| Skyvva API Version | V3 |
| Integration | Your SKYVVA Integration |
| Interface | AccountContactSkyvvaBatch_IN |
| Mode | Skyvva Batch |
| Request Format | XML |
| Response Format | XML |
| Skyvva App Version | your Salesforce package version, e.g. 2.51.0 |
| Salesforce Api Version | 59.0 (or your org's current API version) |
Figure 9: SkyvvaSalesforce receiver channel — Skyvva tab, Mode = Skyvva Batch.
2.3.3 Skyvva Tab — Adapter Settings
| Field | Value |
|---|---|
| Logging option | Default |
| Enable retry for fatal connectivity errors | Unchecked (leave disabled for this test) |
| HTTP client timeout (sec) | 60 |
Figure 10: Integration flow deployed.
2.4 Get the SAP CPI Endpoint URL
Go to CPI → Monitoring → Manage Integration Content, locate the deployed integration flow, and copy its endpoint URL.
Figure 11: Manage Integration Content — endpoint URL.
Note: The endpoint URL shape depends on the tenant generation — Neo tenants usehttps://{{TenantId}}-iflmap.hcisbp.<region>.hana.ondemand.com/http/<Address>, current SAP BTP Integration Suite (Cloud Foundry) tenants usehttps://{{TenantId}}.<runtime-cluster>.cfapps.region>.hana.ondemand.com/http/<Address>. Always copy the exact URL from your own tenant's Manage Integration Content panel rather than assembling it by hand.
3. Testing with Postman
Use the endpoint URL from step 2.4. Send a payload with enough Account/Contact records to see the packaging behavior — a request smaller than Package_Size__c (§1.3) results in one direct REST call to Salesforce; a larger one splits into multiple calls, each becoming its own basket. This example pushes 4,460 Account records (each with a nested Contact) against Package_Size__c = 15 — enough to exercise the packaging behavior many times over rather than just once.
Create a new request with the following configuration:
| Setting | Value |
|---|---|
| Method | POST |
| URL | Your SAP CPI endpoint URL |
| Authorization | Authentication configured for the HTTPS Sender |
| Content-Type | Match the configured Request Format |
Request Format = XML
configure the header as:
Content-Type: application/xml
Note: For a small test payload, use Postman's raw body mode and paste the XML directly — the dropdown next toraw(Text/JSON/XML/…) sets theContent-Typeheader for you automatically. For a large payload, pasting that much text into the raw editor isn't practical; use Body → binary instead, select the XML file from disk, and set theContent-Type: application/xmlheader yourself on the Headers tab — binary mode has no type dropdown of its own, so nothing sets it for you. The file content sent is identical either way; only how you attach it to the request differs.
Because this interface's hierarchical shape (Account with nested Contact records, external IDs skyvvasolutions__ERP_DEBTOR_ID__c/skyvvasolutions__ERP_CONTACT_ID__c) is the same shape used in the Bulk and Auto-Switch tutorials, the same sample payload works here too — the only difference is which interface it's addressed to, resolved on the CPI side via the receiver channel's Interface field (§2.3.2), not from anything in the body itself:
<?xml version="1.0" encoding="UTF-8"?>
<Accounts>
<Account>
<ERP_DEBTOR_ID__c>ACC-000001</ERP_DEBTOR_ID__c>
<Name>CPI Test Account 1</Name>
<Phone>+49-89-2867825</Phone>
<BillingStreet>CPI Test Street</BillingStreet>
<BillingCity>Frankfurt</BillingCity>
<BillingPostalCode>42098</BillingPostalCode>
<BillingCountry>DE</BillingCountry>
<Contact>
<ERP_CONTACT_ID__c>ACC-000001-C01</ERP_CONTACT_ID__c>
<FirstName>Max</FirstName>
<LastName>Mueller</LastName>
<Email>max.mueller.1.1@example.com</Email>
<Phone>+49-89-2719583</Phone>
</Contact>
<!-- ... more Contact elements for this Account ... -->
</Account>
<!-- ... more Account elements, same shape — this example's test file has
4,460 Account elements total, well past Package_Size__c = 15 so many
packages/baskets are created, not just one ... -->
</Accounts>
With a 4,460-record file this large, use Body → binary in Postman (see the note above) rather than pasting it into the raw editor.
With Package_Size__c = 15 and 4,460 root Account records submitted, expect 298 baskets: 297 full baskets of 15 records each (4,455 records), plus one final basket of the remaining 5 records (4,460 − 4,455 = 5).
Figure 12: POSTMAN request and response.
Skyvva Batch mode dispatches to the same code path as plain Asynchronous processing (
IntegrationV3Event/IntegrationBatchHandler), which sends each package as a direct REST call to Salesforce's V4/IntegrateWithIMessage endpoint (mode=Batch) — not the Bulk API. The response is the same "basket created" confirmation you'd see from Auto-Switch's own Batch tier: a JSON body confirming the basket was queued (e.g. "message":"Basket has been created successfully", "BasketStatus":"Init"), not the raw Salesforce Bulk API BatchInfo array that Skyvva Bulk mode returns. This only confirms the package was accepted — not that every record has finished processing yet.
4. Monitoring
4.1 SAP CPI
Go to CPI → Monitor → Monitor Message Processing and verify the message completed successfully.
Figure 13: CPI Monitor Message Processing.
4.2 Salesforce
Go to Salesforce → Message Monitoring to confirm the message and resulting Account/Contact records.
Because this interface has Batch_Mode__c checked (§1.3), it will also appear in the Batch Control Board → Working Basket — the same board Auto-Switch's Batch tier uses, since both dispatch through the identical IntegrationV3Event/IntegrationBatchHandler mechanism on the Salesforce side.
Navigate to: Batch Control Board → Working Basket
Locate the batches created for AccountContactSkyvvaBatch_IN — with the 4,460-record payload above, expect 298 baskets (§3). Each may initially have the status Init.
Select a batch and click Reprocess.
*Figure 14: Batch Control Board — Working Basket for AccountContactSkyvvaBatch_IN, showing 298 Working Baskets totaling 4,460 batch records.*
After processing is complete, verify that the Account and Contact records were created or updated successfully.
Summary
The complete integration flow is:
POSTMAN
↓
HTTPS Sender
↓
SAP CPI Integration Flow
↓
SkyvvaSalesforce Receiver (Mode = Skyvva Batch)
↓
SKYVVA Inbound Interface (Batch_Mode__c = true)
↓
Package (sized at Package_Size__c — §1.3)
↓
Salesforce Account / Contact
Configuration Summary
| Component | Configuration |
|---|---|
| SKYVVA Interface | Inbound, Asynchronous, Upsert |
| Batch Mode | Checked |
Transfer Package Size (Package_Size__c) | 15 |
| SKYVVA API Version | V3 |
| Mode | Skyvva Batch |
| Request/Response Format | XML |
| Example payload / expected baskets | 4,460 Account records → 298 baskets (297 × 15 + 1 × 5) |
The package size is controlled entirely by the interface's own Package_Size__c field (§1.3) and is independent of the CPI channel's own settings — once Mode = Skyvva Batch routes a request here, how it gets chunked into packages is Salesforce-side configuration, not something adjusted from SAP CPI.