> For the complete documentation index, see [llms.txt](https://docs.cybus.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.cybus.io/2-4-2/guides/system-connectivity/mes-erp-business-systems/sap-s4hana-integration.md).

# SAP S/4HANA Integration

This guide describes how to integrate SAP S/4HANA with Connectware. You configure a service commissioning file that polls production orders from the OData APIs of SAP S/4HANA and posts production order confirmations from the shop floor in return. A complete example file is available at the end of this guide.

## Objectives

* Establishing an authenticated connection between Connectware and the SAP S/4HANA OData APIs.
* Polling production orders from SAP S/4HANA into the MQTT topic hierarchy.
* Posting production order confirmations from the shop floor to SAP S/4HANA.
* Understanding the CSRF token requirement for OData write requests.

## Prerequisites

To follow this guide, you will need the following:

* A running instance of Cybus Connectware.
* Access to a SAP S/4HANA Cloud tenant or a SAP S/4HANA system, including the authorization to set up API access. For SAP S/4HANA Cloud, this means creating a communication arrangement. For SAP S/4HANA on-premise, this means activating the OData services and providing a technical user.
* Access to the [Admin UI](/2-4-2/access/admin-ui.md) with sufficient [user permissions](/2-4-2/access/user-management.md).
* Basic knowledge of MQTT and the Connectware [services](/2-4-2/data-flows/services.md) concept (for example, [service commissioning files](/2-4-2/data-flows/service-commissioning-files.md), [connections](/2-4-2/data-flows/service-commissioning-files/resources/cybus-connection.md), and [endpoints](/2-4-2/data-flows/service-commissioning-files/resources/cybus-endpoint.md)).

## Connectware and SAP S/4HANA Integration

SAP S/4HANA exposes its business objects as OData REST APIs, documented in the [SAP Business Accelerator Hub](https://api.sap.com/products/SAPS4HANACloud). Connectware communicates with these APIs through the [HTTP/REST connector](/2-4-2/connectors/enterprise-connectors/http-rest.md), which supports continuous polling, on-demand requests, and pushing data.

This guide uses two production planning APIs as a realistic example:

* [**Production Order API**](https://api.sap.com/api/API_PRODUCTION_ORDER_2_SRV/overview) (`API_PRODUCTION_ORDER_2_SRV`): Reads production orders with their details. Connectware polls this API and publishes the orders to an MQTT topic, where dashboards, MES clients, or edge applications can pick them up.
* [**Production Order Confirmation API**](https://api.sap.com/api/API_PROD_ORDER_CONFIRMATION_2_SRV/overview) (`API_PROD_ORDER_CONFIRMATION_2_SRV`): Creates confirmations for production order operations. Connectware subscribes to confirmation messages from the shop floor and posts them to this API.

The same pattern applies to any other OData API of SAP S/4HANA, such as material documents or maintenance notifications. Exchange the API path, the entity name, and the payload.

In SAP S/4HANA Cloud, API access is set up through a [communication arrangement](https://help.sap.com/docs/SAP_S4HANA_CLOUD/0f69f8fb28ac4bf48d2b57b9637e81fa/fab3fd449cf74c6384622b98831e989e.html). A communication arrangement activates a communication scenario, which bundles a set of APIs, and links it to a communication system and a communication user. The overview page of each API in the SAP Business Accelerator Hub lists the communication scenario that contains it. For example, the Production Order Confirmation API is part of the scenario Production Planning Integration (`SAP_COM_0104`).

The MQTT topics in this guide follow an ISA-95-style equipment hierarchy (`<enterprise>/<site>/<area>/<line>/<cell>`). The confirmation mapping subscribes with wildcards across all levels, so any machine in the hierarchy can post confirmations without changing the integration.

### SAP S/4HANA Connection Properties

The connection to SAP S/4HANA requires the API hostname and the credentials of the communication user. We add them as parameters to the service commissioning file, so you can set them when you install the service.

Do not worry about copying the service commissioning file snippets together into one, the complete example file is available at the end of this guide.

* `s4ApiHost`: The API hostname of your SAP S/4HANA system, without the scheme. For SAP S/4HANA Cloud, this is the hostname with the `-api` suffix. For example, `my300000-api.s4hana.cloud.sap`.
* `commUserName` and `commUserPassword`: The credentials of the communication user from your communication arrangement.
* `productionPlant`: The plant whose production orders Connectware polls. For example, `1010`.
* `pollInterval`: The polling interval in milliseconds. Defaults to `60000`.
* `topicRoot`: The root of the MQTT topic hierarchy. Defaults to `enterprise`.

{% code lineNumbers="true" %}

```yaml
parameters:
  s4ApiHost:
    description: API hostname of your SAP S/4HANA system
    type: string
    default: my300000-api.s4hana.cloud.sap

  commUserName:
    description: Name of the communication user
    type: string

  commUserPassword:
    description: Password of the communication user
    type: string

  productionPlant:
    description: Production plant used to filter production orders
    type: string
    default: '1010'

  pollInterval:
    description: Polling interval for production orders in milliseconds
    type: integer
    default: 60000

  topicRoot:
    description: Root of the MQTT topic hierarchy
    type: string
    default: enterprise
```

{% endcode %}

### SAP S/4HANA Connection

To connect to the SAP S/4HANA OData APIs, we set up a `Cybus::Connection` resource that uses the HTTP/REST connector with basic authentication. Basic authentication with a communication user is the most direct way to consume SAP S/4HANA Cloud APIs and works the same way for a technical user on SAP S/4HANA on-premise. The `Accept: application/json` header instructs the OData services to respond with JSON instead of the XML default.

{% code lineNumbers="true" %}

```yaml
resources:
  s4Connection:
    type: Cybus::Connection
    properties:
      protocol: Http
      connection:
        scheme: https
        host: !ref s4ApiHost
        port: 443
        auth:
          username: !ref commUserName
          password: !ref commUserPassword
        headers:
          Accept: application/json
```

{% endcode %}

For an overview of all connection properties, see [HTTP Connection Properties](/2-4-2/connectors/enterprise-connectors/http-rest/httpconnection.md).

#### Alternative: OAuth 2.0 Client Credentials

SAP S/4HANA Cloud communication arrangements can also expose APIs with OAuth 2.0 client credentials. The HTTP/REST connector supports this through the [OAuth 2.0 Client Credentials Grant](https://docs.cybus.io/2-4-2/guides/system-connectivity/mes-erp-business-systems/pages/Hij6TsDxB4GxfyynBwLn#oauth-2.0-client-credentials-grant), and Connectware refreshes the token automatically before it expires. You find the client ID and the token service URL in the OAuth 2.0 details of the inbound communication in your communication arrangement. In this case, replace the `auth` property with the following configuration:

{% code lineNumbers="true" %}

```yaml
oauthClientCredentials:
  auth_url: https://my300000-api.s4hana.cloud.sap/sap/bc/sec/oauth2/token
  client_id: !ref oauthClientId
  client_secret: !ref oauthClientSecret
```

{% endcode %}

### Polling Production Orders from SAP S/4HANA

To read production orders, we define an endpoint that polls the `A_ProductionOrder_2` entity of the Production Order API at the configured interval (see [Subscribing to Data](/2-4-2/connectors/enterprise-connectors/http-rest.md#subscribing-to-data-continuous-polling)). The `query` property adds OData query options to the request: `$filter` limits the result to one plant, `$top` limits the number of returned orders, and `$format` requests JSON.

{% code lineNumbers="true" %}

```yaml
productionOrderEndpoint:
  type: Cybus::Endpoint
  properties:
    protocol: Http
    connection: !ref s4Connection
    subscribe:
      path: /sap/opu/odata/sap/API_PRODUCTION_ORDER_2_SRV/A_ProductionOrder_2
      interval: !ref pollInterval
      query:
        $filter: !sub "ProductionPlant eq '${productionPlant}'"
        $top: '50'
        $format: json

productionOrderMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          endpoint: !ref productionOrderEndpoint
        publish:
          topic: !sub '${topicRoot}/erp/s4hana/production-orders'
        rules:
          - transform:
              expression: 'value.d.results'
```

{% endcode %}

The HTTP/REST connector wraps every response in a JSON structure with a `timestamp` and a `value` property (see [Response Message Format](/2-4-2/connectors/enterprise-connectors/http-rest.md#response-message-format)), and the OData v2 protocol wraps the entity list in a `d.results` envelope. The optional `transform` rule unwraps both, so the plain list of production orders is published to `enterprise/erp/s4hana/production-orders`. Remove the rule if you want to keep the full envelope.

You can narrow down the polled data with additional OData query options, for example `$select` to return only specific fields, or a `$filter` on the order status. For the available fields, refer to the [Production Order API](https://api.sap.com/api/API_PRODUCTION_ORDER_2_SRV/overview) in the SAP Business Accelerator Hub.

### Posting Production Order Confirmations to SAP S/4HANA

To send data from the shop floor to SAP S/4HANA, we define a write endpoint for the `ProdnOrdConf2` entity of the Production Order Confirmation API and a mapping that feeds it from the MQTT topic hierarchy. The HTTP/REST connector expects the request body in the `body` property of the message (see [Publishing Data to REST Servers](/2-4-2/connectors/enterprise-connectors/http-rest.md#publishing-data-to-rest-servers)). The `transform` rule wraps the incoming payload accordingly, so machines can publish their confirmations without knowing about this convention.

{% code lineNumbers="true" %}

```yaml
confirmationEndpoint:
  type: Cybus::Endpoint
  properties:
    protocol: Http
    connection: !ref s4Connection
    write:
      path: /sap/opu/odata/sap/API_PROD_ORDER_CONFIRMATION_2_SRV/ProdnOrdConf2
      headers:
        X-Requested-With: 'X'

confirmationMapping:
  type: Cybus::Mapping
  properties:
    mappings:
      - subscribe:
          topic: !sub '${topicRoot}/+site/+area/+line/+cell/confirmations'
        publish:
          endpoint: !ref confirmationEndpoint
        rules:
          - transform:
              expression: '{ "body": $ }'
```

{% endcode %}

Any message published to a matching topic, for example `enterprise/hamburg/assembly/line-1/press-01/confirmations`, now creates one confirmation in SAP S/4HANA. The payload must follow the request schema of the `ProdnOrdConf2` entity. OData v2 represents quantities as strings:

{% code lineNumbers="true" %}

```json
{
  "OrderID": "1003404",
  "Sequence": "0",
  "OrderOperation": "0010",
  "ConfirmationYieldQuantity": "5",
  "ConfirmationUnit": "PC",
  "FinalConfirmation": false
}
```

{% endcode %}

For the complete schema, refer to the [Production Order Confirmation API](https://api.sap.com/api/API_PROD_ORDER_CONFIRMATION_2_SRV/overview) in the SAP Business Accelerator Hub.

### Handling the CSRF Token Requirement

SAP Gateway protects modifying OData requests (POST, PATCH, DELETE) against cross-site request forgery (CSRF). By default, a client must first send a GET request with the header `x-csrf-token: fetch`, and then repeat the returned token together with the session cookies on every modifying request. The HTTP/REST connector sends stateless requests and does not perform this token exchange. Polling and reading are not affected, but a POST request to a CSRF-protected OData service fails with the status `403 Forbidden` and the message `CSRF token validation failed`.

You have the following options:

* **SAP S/4HANA on-premise or private edition**: An administrator can deactivate the CSRF token check for the dedicated OData service in transaction SICF by setting the `~CHECK_CSRF_TOKEN` parameter to `0`, as described in [SAP Knowledge Base Article 2751277](https://userapps.support.sap.com/sap/support/knowledge/en/2751277). The gateway then accepts modifying requests that carry the `X-Requested-With` header instead, which the write endpoint in this guide already sets.
* **SAP S/4HANA Cloud Public Edition**: The CSRF token check cannot be deactivated. Route write requests through a component that performs the token exchange, for example an integration flow in SAP Integration Suite, and point the write endpoint of this guide to that component instead of the OData service directly.

{% hint style="warning" %}
Deactivating the CSRF token check reduces the protection of the OData service and SAP does not recommend it for production systems. Restrict the deactivation to dedicated services that are only reachable by trusted server-side clients such as Connectware. For OData v4 services, the check cannot be deactivated at all.
{% endhint %}

## Verifying the Integration

1. Install the service and set the parameters to the values from your communication arrangement.
2. Check that the connection is in the **Connected** state on the service details page in the Admin UI.
3. Open the [Data Explorer](/2-4-2/monitoring/data-explorer.md) and subscribe to `enterprise/erp/s4hana/production-orders`. After the polling interval has passed, the current production orders of your plant appear.
4. Publish a confirmation payload, for example the one shown in this guide, to `enterprise/hamburg/assembly/line-1/press-01/confirmations` with an MQTT client or the Admin UI.
5. Check the result on the `/res` topic of the confirmation endpoint in the Data Explorer. On success, the message contains a `result` property with the response of SAP S/4HANA. If SAP S/4HANA rejects the request, the message contains an `error` property with the HTTP status, for example the CSRF error described in this guide.
6. In SAP S/4HANA, open the production order and check that the confirmation has been posted against the operation.

## Service Commissioning File Example

{% file src="/files/5xXOwEmMusCaan0JM3T4" %}

{% code title="sap-s4hana-example.yml" lineNumbers="true" expandable="true" %}

```yaml
---
# ----------------------------------------------------------------------------
# Service Commissioning File
# ----------------------------------------------------------------------------
# Copyright: Cybus GmbH
# Contact: support@cybus.io
# ----------------------------------------------------------------------------
# SAP S/4HANA Integration (Example)
# ----------------------------------------------------------------------------

description: >
  Service commissioning file for exchanging data between Connectware and
  SAP S/4HANA via its OData REST APIs (Example)

metadata:
  name: SAP S4HANA Integration
  provider: cybus
  homepage: https://www.cybus.io
  version: 1.0.0

parameters:
  s4ApiHost:
    description: API hostname of your SAP S/4HANA system
    type: string
    default: my300000-api.s4hana.cloud.sap

  commUserName:
    description: Name of the communication user
    type: string

  commUserPassword:
    description: Password of the communication user
    type: string

  productionPlant:
    description: Production plant used to filter production orders
    type: string
    default: '1010'

  pollInterval:
    description: Polling interval for production orders in milliseconds
    type: integer
    default: 60000

  topicRoot:
    description: Root of the MQTT topic hierarchy
    type: string
    default: enterprise

resources:
  # Connection to the SAP S/4HANA OData APIs using basic authentication
  s4Connection:
    type: Cybus::Connection
    properties:
      protocol: Http
      connection:
        scheme: https
        host: !ref s4ApiHost
        port: 443
        auth:
          username: !ref commUserName
          password: !ref commUserPassword
        headers:
          Accept: application/json

  # Polls production orders of one plant from SAP S/4HANA
  productionOrderEndpoint:
    type: Cybus::Endpoint
    properties:
      protocol: Http
      connection: !ref s4Connection
      subscribe:
        path: /sap/opu/odata/sap/API_PRODUCTION_ORDER_2_SRV/A_ProductionOrder_2
        interval: !ref pollInterval
        query:
          $filter: !sub "ProductionPlant eq '${productionPlant}'"
          $top: '50'
          $format: json

  productionOrderMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            endpoint: !ref productionOrderEndpoint
          publish:
            topic: !sub '${topicRoot}/erp/s4hana/production-orders'
          rules:
            # Optional: unwraps the OData envelope so that the plain list
            # of production orders is published
            - transform:
                expression: 'value.d.results'

  # Posts production order confirmations to SAP S/4HANA
  confirmationEndpoint:
    type: Cybus::Endpoint
    properties:
      protocol: Http
      connection: !ref s4Connection
      write:
        path: /sap/opu/odata/sap/API_PROD_ORDER_CONFIRMATION_2_SRV/ProdnOrdConf2
        headers:
          # Only evaluated if the CSRF token check of the OData service is
          # deactivated, see the SAP S/4HANA Integration guide for details
          X-Requested-With: 'X'

  confirmationMapping:
    type: Cybus::Mapping
    properties:
      mappings:
        - subscribe:
            topic: !sub '${topicRoot}/+site/+area/+line/+cell/confirmations'
          publish:
            endpoint: !ref confirmationEndpoint
          rules:
            - transform:
                expression: '{ "body": $ }'
```

{% endcode %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.cybus.io/2-4-2/guides/system-connectivity/mes-erp-business-systems/sap-s4hana-integration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
