18. SkyvvaSalesforce Receiver Adapter — Platform Event Publishing
1. Overview
This tutorial uses the SkyvvaSalesforce receiver adapter → Skyvva → Platform Event - Publishing to send a posted-invoice notification to Salesforce. CPI validates and maps the invoice; a Salesforce Flow receives the event and creates an Invoice Notice.
Postman represents the ERP system in this tutorial. ERP means Enterprise Resource Planning, such as SAP S/4HANA or SAP ECC, where invoices are created and posted. Use Postman to send the sample invoice and view CPI's response; no real ERP connection is required.
The example uses JSON for input/output and XML for validation and Message Mapping, with standard CPI steps.
2. Context Before You Start
2.1 Business situation and why use it
A distributor manages invoicing in ERP and customer relationships in Salesforce. Sales representatives need to see posted invoices without waiting for a nightly export. The ERP sends the customer number, invoice number, amount, currency, and posting time after its invoice transaction has committed.
| Business value | Example |
|---|---|
| ERP customer number | 0000100451 |
| Invoice number | 90001067 |
| Invoice amount | USD 1250.75 |
| Business message ID | ERP-INVOICE-90001067-POSTED-01 |
This is a fictional invoice-notification example. ERP remains responsible for accounting; the event tells Salesforce that posting has already occurred.
Use events for asynchronous follow-up work. Use a record operation when the caller needs an immediate Salesforce record result.
2.2 How the flow works
ERP → Receive Posted Invoice → InvoiceJsonToXml → ValidateInvoiceXml
→ CheckInvoiceRules ── valid → MapInvoiceToEvent → SetEventContentType
→ PublishInvoice → SetResponseHeaders → Return Publication Confirmation → ERP
CheckInvoiceRules ── default → RejectInvoice (Error End)
PublishInvoice ⇄ SKYVVA receiver: Platform Event - Publishing ⇄ Salesforce event bus
Salesforce event bus → Platform Event–Triggered Flow → Invoice Notice
The SKYVVA Integration and Interface identify the target event. CPI performs the mapping and publishes through Salesforce Pub/Sub.
ERP receives a response after publication. It does not wait for the Salesforce subscriber to finish. status = SUCCESS acknowledges event publication; it does not confirm that an Invoice Notice exists.
3. Prerequisites
- A Salesforce org with SKYVVA installed, Pub/Sub access, and sufficient event allocations.
- A SkyvvaSalesforce receiver adapter version exposing Skyvva → Platform Event - Publishing.
- An OAuth application with Client Credentials enabled and an authorized run-as integration user.
- Integration-user API access, read access to the selected SKYVVA Integration/Interface and queried metadata fields, and Create permission for the Platform Event.
- Network access for Salesforce login/metadata queries and Pub/Sub at
api.pubsub.salesforce.com:7443. - An authorized Postman caller for the CPI HTTPS endpoint and a Salesforce administrator to configure the subscriber.
4. Create the Salesforce event
The custom Platform Event defines the notification “ERP has posted this invoice” and the fields subscribers receive, such as customer, invoice number and amount.
You can reuse a suitable existing event. Keep its API name and fields consistent across the SKYVVA Interface, CPI mapping and subscriber Flow.
- In Salesforce Setup, search Platform Events and select New Platform Event.
- Enter Label
ERP Invoice Posted, Plural LabelERP Invoices Posted, and Object NameERP_Invoice_Posted. - Confirm API name
ERP_Invoice_Posted__e, high-volume event support, and Deployment Status Deployed. - Keep Publish Behavior = Publish Immediately and save. This setting does not coordinate the Pub/Sub call with ERP; send only after ERP commits the invoice.
- Add the custom fields below through the event's Custom Fields & Relationships → New action.
| Label | API name | Type and size |
|---|---|---|
| Message ID | Message_ID__c | Text(80) |
| ERP Customer ID | ERP_Customer_ID__c | Text(30) |
| Invoice Number | Invoice_Number__c | Text(30) |
| Gross Amount | Gross_Amount__c | Number: Length 16, Decimal Places 2 |
| Currency Code | Currency_Code__c | Text(3) |
| Invoice Status | Invoice_Status__c | Text(20) |
| Posted At | Posted_At__c | Text(30), UTC ISO timestamp contract |
All seven fields are required by this example. Section 8 configures validation for positive USD invoices with status POSTED.
Grant the integration user Create access to the event and configure the subscriber's access to its destination object.
Figure 1. Custom fields of the ERP Invoice Posted event.
5. Configure the SKYVVA Integration and Interface
- Open the SKYVVA Integration area in Salesforce and create an Integration named
ERP Invoice Events, or use an existing dedicated Integration. - Within that Integration, create an Interface with Interface Name =
ERP Invoice Posted. Use the business interface name, not the generated Salesforce record number. - Select Interface Direction = InBound because the notification enters Salesforce.
- Set Source/Target Name to
ERP_Invoice_Posted__e. Depending on the screen, this field can appear as Source Name or Salesforce Object. Confirm its saved value is the event API name. - Select Operation Type = Publish Salesforce Event where required by the Interface form. Complete required fields according to your org's Interface creation policy, save, and make the Interface available to the integration user.
- Confirm this Interface name is unique within the named Integration and that its Integration relationship points to
ERP Invoice Events.
The publisher uses these Integration/Interface names to resolve /event/ERP_Invoice_Posted__e. No Channel Name entry is needed on the receiver screen.
No SKYVVA mapping rows or response Interface are required; field mapping is configured in CPI.
Why is External Mapping not used? This operation publishes directly through Salesforce Pub/Sub. It uses the Interface to identify the event and does not run the SKYVVA mapping engine. CPI Message Mapping prepares the event fields, so enabling the Interface's External Mapping flag does not change this publishing path.
If you change the event API name on an existing Interface, restart or redeploy the iFlow to refresh its cached selection.
Figure 2. SKYVVA Interface identifying the invoice event.
6. Create a simple Salesforce subscriber
To make the received event visible, create a Platform Event–Triggered Flow that saves an Invoice Notice:
Start: ERP Invoice Posted → Create Invoice Notice
6.1 Create the destination object
The custom Invoice Notice object stores the received invoice information so users can view, search and report on it. The subscriber Flow copies event values into this record; publication alone does not create it.
For a real business process, you can use a suitable existing object and adjust the Flow mappings instead.
In Setup → Object Manager → Create → Custom Object, create Invoice Notice (Plural Label Invoice Notices, Object Name Invoice_Notice). Set its Record Name to Invoice Notice Number, Type to Auto Number, Display Format to IN-{00000}, and Starting Number to 1.
Under Fields & Relationships, add these fields. Reuse the object and fields if you already created them.
| Field API name | Type |
|---|---|
Message_ID__c | Text(80), Unique |
ERP_Customer_ID__c | Text(30) |
Invoice_Number__c | Text(30) |
Gross_Amount__c | Number: Length 16, Decimal Places 2 |
Currency_Code__c | Text(3) |
Posted_At__c | Text(30) |
Processing_Status__c | Text(30) |
Give the users verifying the result access to Invoice Notice and its fields, and make its records available through a custom tab or your Salesforce application.
6.2 Configure the Flow
- Open Setup → Flows → New Flow → Platform Event–Triggered Flow.
- In Start, select the invoice event created in section 4. Use the actual API name in your org (
ERP_Invoice_Posted__e, or your existingERP_Invoices_Posted__e). - Add Create Records with Label
Create Invoice Noticeand API NameCreate_Invoice_Notice. - Choose One record. Under How to set record field values, select Manually ("Select an object and configure the record values manually"), then choose Invoice Notice as the object. Select the incoming
$Recordfields through the value resource picker for each mapping. Add these mappings:
| Invoice Notice field | Value resource or literal |
|---|---|
Message_ID__c | {!$Record.Message_ID__c} |
ERP_Customer_ID__c | {!$Record.ERP_Customer_ID__c} |
Invoice_Number__c | {!$Record.Invoice_Number__c} |
Gross_Amount__c | {!$Record.Gross_Amount__c} |
Currency_Code__c | {!$Record.Currency_Code__c} |
Posted_At__c | {!$Record.Posted_At__c} |
Processing_Status__c | Literal text Recorded |
- Leave the auto-number Name and any existing optional Account lookup unmapped.
- Connect Start → Create Invoice Notice. In Auto-Layout, add the element using + beneath Start; in Free-Form, draw the connection. The successful branch ends after Create Records.
- Save as Record ERP Invoice Notice, API Name
Record_ERP_Invoice_Notice, resolve validation errors, and activate the Flow.
Ensure only the intended subscriber version is active for the test.
6.3 Verify receipt
After publishing the valid sample in section 10, allow time for asynchronous processing, then find the Invoice Notice by Message ID. Verify invoice 90001067, customer 0000100451, amount 1250.75, currency USD, posting time 2026-10-10T07:30:00Z, and status Recorded.
Use a new Message ID for each new test notification. Reusing one can fail notice creation because its Message ID field is unique.
Figure 3. Activated Salesforce subscriber Flow for the invoice event.
7. Create the SAP Integration Suite iFlow and connection
Create ERP Posted Invoice to Salesforce Event using the diagram in section 2.2. Configure its sender and receiver below, then add the processing steps from sections 8–9.
7.1 HTTPS sender
| Setting | Example configuration |
|---|---|
| General | Name ReceivePostedInvoice |
| Connection → Address | /erp/invoices/posted |
| Authorization | User Role; tenant-approved caller role, commonly ESBMessaging.send |
| Incoming method/body | Caller sends POST with Content-Type application/json |
| CSRF and other optional settings | Follow the tenant's approved inbound policy; if CSRF is enabled, the caller obtains and sends token/cookies |
Use the deployed CPI endpoint and caller authentication, separate from Salesforce receiver credentials. Set Integration Process Transaction Handling to Not Required.
7.2 Receiver credentials and Connection tab
In SAP Integration Suite Security Material, deploy a User Credentials artifact named skyvva-client-credentials. Set User to the Salesforce application Client ID and Password to its Client Secret. This adapter reads that artifact type for Client Credential authentication.
| Tab/field | Value |
|---|---|
| General | Receiver channel name PublishInvoiceEvent; SkyvvaSalesforce adapter |
| Connection → Authentication Type | OAuth2 |
| Connection → OAuth2 Flow | Client Credential |
| Connection → Login Url | Your Salesforce My Domain base address, for example https://your-domain.my.salesforce.com |
| Connection → Client Credential | skyvva-client-credentials |
| Connection → User Credential | Hidden for the selected OAuth2 flow |
Do not append /services/oauth2/token to Login Url. The administrator must enable the application flow and configure its run-as user before you test.
7.3 Receiver Processing tab
| Field/group | Value | Why |
|---|---|---|
| Processing Type | Skyvva | Uses SKYVVA Interface metadata to locate the event |
| Operation | Platform Event - Publishing | Selects the event publisher |
| Integration | ERP Invoice Events | Must match the saved Integration name |
| Interface | ERP Invoice Posted | Must match Interface Name within that Integration |
| Format → Request Format | Application/XML | Matches the graphical mapping output |
| Format → Response Format | Application/JSON | Supplies the acknowledgement returned unchanged to ERP |
| Adapter Settings → Logging option | Default | Normal SAP Integration Suite adapter logging |
| Enable retry for fatal connectivity errors | Disabled | This HTTP setting does not supply a complete Pub/Sub business-retry procedure |
| HTTP client timeout (sec) | Keep default 60 | HTTP login/metadata setting; it is not a Pub/Sub publish deadline |
The Interface supplies the event name. Leave unrelated API Version/Mode settings unchanged. Reconcile an uncertain publication before retrying.
Figure 4. Receiver settings for Platform Event Publishing.
8. Map the ERP invoice to one event
Convert the invoice to XML, validate it, then map its fields to the Salesforce event.
8.1 Agree the input contract
Send one invoice object with text identifiers, a numeric amount and a UTC timestamp ending in Z. ERP must convert timestamps to UTC before sending; this route does not perform timezone conversion.
Copy the following JSON into Postman. You can also save it locally as erp-invoice-utc.json:
{
"messageId": "ERP-INVOICE-90001067-POSTED-01",
"customerNumber": "0000100451",
"invoiceNumber": "90001067",
"grossAmount": 1250.75,
"currency": "USD",
"status": "POSTED",
"postedAt": "2026-10-10T07:30:00Z"
}
Keep identifiers quoted to preserve leading zeros. Enforce JSON types in ERP/API input validation: after XML conversion, the validator cannot distinguish JSON numbers from quoted numeric strings.
8.2 Convert ERP JSON to XML
Add a JSON to XML Converter named InvoiceJsonToXml after Start:
| Processing setting | Value |
|---|---|
| Add XML Root Element | Selected |
| Name | Invoice |
| Root namespace | Empty |
| Use Namespace Mapping | Disabled |
Its output should contain one Invoice root and the seven ERP field names. Save the following sample as erp-invoice.xml for mapping simulation; Postman sends the JSON above.
<?xml version="1.0" encoding="UTF-8"?>
<Invoice>
<messageId>ERP-INVOICE-90001067-POSTED-01</messageId>
<customerNumber>0000100451</customerNumber>
<invoiceNumber>90001067</invoiceNumber>
<grossAmount>1250.75</grossAmount>
<currency>USD</currency>
<status>POSTED</status>
<postedAt>2026-10-10T07:30:00Z</postedAt>
</Invoice>
8.3 Validate before publishing
Have your integration developer prepare and upload ERPInvoiceValidation.xsd using the rules below. This schema defines the required fields and allowed values.
| Field | Check before publishing |
|---|---|
| Message ID | Required text, maximum 80 characters |
| Customer number | Required text containing 1–30 digits; keep leading zeros |
| Invoice number | Required text, maximum 30 characters |
| Gross amount | Greater than zero, below 10000000000000000, with at most two meaningful decimal places |
| Currency | USD |
| Status | POSTED |
| Posted at | Valid UTC date/time ending in Z |
| Message structure | One invoice with exactly the seven expected fields, each appearing once; allow any field order |
Add XML Validator → ValidateInvoiceXml, select the schema and keep Prevent Exception on Failure disabled. Message Mapping alone does not run this validation.
After the validator add a Router named CheckInvoiceRules. On the valid route choose Expression Type = XML and use this XPath condition:
not(/Invoice/*[
normalize-space(substring(string(.), 1, 1)) = ''
or normalize-space(substring(string(.), string-length(string(.)), 1)) = ''
])
and string-length(/Invoice/postedAt) <= 30
This is an XPath validation condition, not a Groovy script. It rejects field values with leading or trailing XML whitespace and checks that postedAt is no longer than 30 characters. Connect the valid route to Message Mapping and the Default Route to an Error End named RejectInvoice.
This extra check supports the tutorial’s input rules; Platform Event publishing itself does not require this Router. If your sending system already enforces these rules, you can omit CheckInvoiceRules and its RejectInvoice branch, then connect ValidateInvoiceXml → MapInvoiceToEvent directly. Keep the XML Validator.
8.4 Create the graphical Message Mapping
Have your integration developer prepare the two mapping XSDs from the field table below. Add Message Mapping → MapInvoiceToEvent, create/select its mapping resource and choose:
| Side | Schema | Root |
|---|---|---|
| Source | ERPInvoice.xsd | Invoice |
| Target | InvoiceEvent.xsd | InvoiceEvent |
Use no target namespace. These schemas describe the mapping; the Salesforce fields are created separately in section 4.
Connect each ERP field to the matching Salesforce field:
| ERP field | Salesforce event field | Value type |
|---|---|---|
| messageId | Message_ID__c | Text |
| customerNumber | ERP_Customer_ID__c | Text; preserve leading zeros |
| invoiceNumber | Invoice_Number__c | Text |
| grossAmount | Gross_Amount__c | Decimal number |
| currency | Currency_Code__c | Text |
| status | Invoice_Status__c | Text |
| postedAt | Posted_At__c | UTC date/time input → text event field |
Save and select the mapping. Run Simulation with erp-invoice.xml from section 8.2 and compare with this expected output:
<InvoiceEvent>
<Message_ID__c>ERP-INVOICE-90001067-POSTED-01</Message_ID__c>
<ERP_Customer_ID__c>0000100451</ERP_Customer_ID__c>
<Invoice_Number__c>90001067</Invoice_Number__c>
<Gross_Amount__c>1250.75</Gross_Amount__c>
<Currency_Code__c>USD</Currency_Code__c>
<Invoice_Status__c>POSTED</Invoice_Status__c>
<Posted_At__c>2026-10-10T07:30:00Z</Posted_At__c>
</InvoiceEvent>
Check the seven fields, leading zeros, amount and timestamp. Section 10 tests the deployed flow.
8.5 Publish the mapped XML
Add a Content Modifier named SetEventContentType after mapping. In Message Header create a Constant Content-Type header with value application/xml; leave the body unchanged. Connect to PublishInvoice, the Request Reply step using the PublishInvoiceEvent SkyvvaSalesforce receiver channel from section 7. Set Request Format = Application/XML and Response Format = Application/JSON.
Send one InvoiceEvent root with its seven field children, without an extra envelope or records array. No XML-to-JSON Converter is needed before publishing.
Figure 5. Complete CPI iFlow for invoice validation, mapping and publication.
Figure 6. Message Mapping from ERP invoice fields to Salesforce event fields.
9. Return publication confirmation to ERP
The response returns to the caller—Postman in this tutorial.
After PublishInvoice, add a Content Modifier named SetResponseHeaders. In Message Header create these Constant entries, leaving the Message Body unchanged:
| Name | Value |
|---|---|
| Content-Type | application/json |
| CamelHttpResponseCode | 200 |
Connect it to the normal End, Return Publication Confirmation, on the successful path.
Return the adapter acknowledgement unchanged:
{"status":"SUCCESS","message":"Platform event published","replayId":"AQID"}
| Response item | Meaning |
|---|---|
| status = SUCCESS | The adapter reports acknowledged event publication. |
| message | The adapter's publication-result description. |
| replayId | Opaque event replay identifier represented as Base64. AQID is illustrative; actual values vary. It is not an invoice or ERP Message ID. |
| HTTP 200 | The request completed under this publication contract; it does not confirm subscriber business processing. |
Keep the acknowledgement body unchanged. Retain the request's original messageId for business reconciliation.
Verify subscriber processing separately by finding the matching Invoice Notice, as described in section 6.3.
Figure 7. Publication acknowledgement displayed in Postman.
Figure 8. Invoice Notice created by the Salesforce subscriber.
10. Testing with Postman
- Save and deploy the iFlow; activate the Salesforce subscriber from section 6.
- Copy the endpoint from Monitor → Manage Integration Content.
- In Postman, select POST, enter that URL and configure the HTTPS sender's required authentication.
- Set Content-Type = application/json. Choose Body → raw → JSON, paste the section 8.1 sample and send.
- Check Postman's response, the CPI execution under Monitor → Monitor Message Processing, and the saved Invoice Notice.
| Test | Expected result |
|---|---|
| Valid UTC sample invoice | HTTP 200 with adapter status SUCCESS, message Platform event published and a nonempty replayId; verify the Invoice Notice separately |
| Missing customer, blank message ID or status DRAFT | XML Validator or Router rejects before publication |
| Non-UTC timestamp, invalid calendar date or timestamp longer than 30 characters | XML Validator or Router rejects before publication |
| Numeric customerNumber or quoted grossAmount in JSON | Enforce JSON types in ERP/API input validation; XML conversion loses those original JSON types |
| Amount 1250.755, zero, negative, or currency other than USD | Contract validation rejects before publication |
| Wrong Integration/Interface, blank source name, or Account as source | Topic resolution fails; no success response |
| Event publishing permission absent | Publication fails; investigate integration-user access |
| Publish or caller timeout | Result can be uncertain; reconcile before resend using the stable Message ID |
Find the notice by business Message ID, not replayId. A Completed CPI execution alone does not confirm subscriber success.
11. Monitoring, alerts, and recovery
| Area | What to monitor and recover |
|---|---|
| ERP source | Retain committed invoice notifications, Message IDs, send attempts, and returned acknowledgements |
| SAP Integration Suite publisher | Monitor message failures, lookup/login/publish errors, and uncertain results; arrange actual operational alerts |
| SKYVVA Interface | Supplies event identity; this direct publisher does not create normal SKYVVA messages for monitoring or reprocessing |
| Salesforce subscriber | If using the example Flow, check activation, missing notices, and record-creation failures |
| Business reconciliation | Match ERP posted invoices to Invoice Notices by Message ID and invoice reference |
Use CPI monitoring for this publisher; normal SKYVVA message monitoring/reprocessing is not created automatically. If a notice is missing, check the Flow's activation, event selection and record-creation errors. Reconcile uncertain publication before resending.
12. Summary
Configuration Summary
| Component | Configuration |
|---|---|
| Receiver | Skyvva → Platform Event - Publishing |
| Integration / Interface | ERP Invoice Events / ERP Invoice Posted |
| Event | ERP_Invoice_Posted__e |
| Formats | ERP input JSON; receiver request Application/XML; receiver response Application/JSON |
| Publication verification | Check the publication acknowledgement |
| Subscriber verification | Find the Invoice Notice by Message ID (section 6.3) |