# SAP OData Connection

> Source: https://docs.synthesized.io/tdk/latest/user_guide/070_integrations/sap/sap_odata_detail
> For the complete documentation index, see [llms.txt](https://docs.synthesized.io/llms.txt).

Use TDK to read from and write to SAP tables over an OData service, without a direct database (JDBC) connection to SAP HANA.

## Overview

The SAP OData connector lets the Synthesized Platform exchange table data with an SAP system through a purpose-built OData v2 service running on the SAP Gateway, rather than over a JDBC connection to the underlying database.

This is useful when:

- Direct database access to SAP HANA is not permitted (network, security, or licensing policy).
- You want SAP to broker access through the application layer and its standard authorizations.
- The platform runs outside the SAP network and can only reach SAP over HTTPS.

> **NOTE**
> This is a **dedicated integration**, not a generic OData client. It talks to a Synthesized-provided ABAP/Gateway service that exposes a fixed set of endpoints for catalog metadata, reading table records, and writing table records. A standard OData service or an arbitrary `$metadata` document will not work — see [Prerequisites](#_prerequisites).

How a connection is used depends on its role in a workflow:

- **Source (input)** — TDK reads records from the OData service and materialises them into a local working directory before transforming them. Used as the input of a masking/subsetting workflow.
- **Target (output)** — TDK writes transformed or generated rows back to the OData service. The service is write-only on this side; TDK does not read data back from the target.

All standard TDK transformation modes (**MASKING**, **GENERATION**, **KEEP**) are supported. Transformation is performed by the TDK pipeline as usual; the OData connector only moves data in and out.

## How It Works

The connector communicates with three endpoints exposed by the SAP Gateway service (`SERVICE_NAME` below is the activated service, e.g. `ZTDK_SRV`):

 
| Endpoint | Purpose |
| --- | --- |
| 
`/dbHeaderSet`

 | 

Catalog metadata — the list of exposed tables with their fields, primary keys, and foreign keys. Read once and cached.

 |
| 

`/readTableRecords`

 | 

Paged read of the rows of a single table.

 |
| 

`/createTableHeaderSet`

 | 

Write of a batch of rows to a single table.

 |

The connection flow is:

1. **Authenticate.** Every request carries an HTTP Basic `Authorization` header and an `X-Requested-With: XMLHttpRequest` header (the latter stops the SAP Gateway redirecting API calls to an HTML login page).
2. **Read metadata.** TDK fetches the whole catalog from `/dbHeaderSet` in one call (`$expand` pulls fields and foreign keys together) and builds the schema: tables, primary keys (fields flagged as key), and foreign keys. Foreign keys pointing at tables that are not exposed by the service are dropped.
3. **Read data (source).** For each table, TDK pages through `/readTableRecords` using `$top`/`$skip` (10,000 rows per page by default), filtering by table name, until the service returns an empty page. Rows are coerced from their ABAP/DDIC types into typed values and stored in a local mirror for transformation.
4. **Write data (target).** For each batch, TDK fetches a CSRF token (`X-CSRF-Token: Fetch`), then ``POST`s the rows to `/createTableHeaderSet``. If the token has expired the request returns `403`; TDK fetches a fresh token and retries once.

The connector retries automatically on transient network errors and server (5xx) responses with exponential backoff, since SAP Gateways can surface `502`/`503`/`504` during long reads.

## Prerequisites

Before configuring a connection, the following must be in place on the SAP side:

- **The Synthesized OData service is installed and activated** on the SAP Gateway, exposing the `/dbHeaderSet`, `/readTableRecords`, and `/createTableHeaderSet` endpoints, and configured to expose the tables you want to work with. Note the service name (e.g. `ZTDK_SRV`).
- **A SAP user** with authorization to call the service and to read (and, for a target connection, write) the exposed tables. Use a dedicated technical/service user — see [Best Practices](#_best_practices).
- **Network access** from the platform (or agent) to the Gateway host and HTTPS port (commonly `443`, or `44300` for an SSL-enabled Gateway).
- **A valid TLS certificate** on the Gateway, trusted by the platform host. If the certificate is self-signed or not yet trusted, you can disable validation for testing — see [TLS Configuration](#_tls_configuration).

## Connection Configuration

### Service URL Format

The connection URL is the **root of the OData service**:

https://<host>:<port>/sap/opu/odata/sap/<SERVICE\_NAME>

 
| Component | Description |
| --- | --- |
| 
`host`

 | 

Hostname or IP of the SAP Gateway.

 |
| 

`port`

 | 

HTTPS port of the Gateway (e.g. `443`, `44300`).

 |
| 

`SERVICE_NAME`

 | 

The activated OData service name (e.g. `ZTDK_SRV`).

 |

Authentication is **username / password** (HTTP Basic). No OAuth, SAML, or client-certificate authentication is supported.

> **NOTE**
> Internally TDK marks an OData connection with an `odata:` URL prefix to route it to this connector. You do not need to add the prefix yourself — enter the plain `[https://…​](https://…​);` service URL in the UI or config. TDK adds and strips the prefix automatically.

### Optional URL parameters

You can append query parameters to the service URL to tune behaviour:

  
| Parameter | Default | Description |
| --- | --- | --- |
| 
`insecureTls`

 | 

`false`

 | 

Set to `true` to skip TLS certificate validation. Use only for testing against systems with self-signed certificates. See [TLS Configuration](#_tls_configuration).

 |
| 

`requestTimeoutMs`

 | 

`60000`

 | 

Per-request timeout in milliseconds. Increase for tables that are slow to page on the Gateway.

 |

Example with parameters:

https://saphost.company.com:44300/sap/opu/odata/sap/ZTDK\_SRV?requestTimeoutMs=120000

## Adding a Data Source

### Via the UI

1. Navigate to **Data Sources**.
2. Click **Add Data Source**.
3. Select the **SAP OData** type.
4. Enter the connection details:
  
   
  | Field | Value |
  | --- | --- |
  | 
  **Name**
  
   | 
  
  A label for the connection.
  
   |
  | 
  
  **API endpoint URL**
  
   | 
  
  The service root, e.g. `[https://your-system/sap/opu/odata/sap/SERVICE_NAME](https://your-system/sap/opu/odata/sap/SERVICE_NAME)`.
  
   |
  | 
  
  **Username**
  
   | 
  
  SAP user with access to the service.
  
   |
  | 
  
  **Password**
  
   | 
  
  Password for that user.
  
   |
5. Click **Test Connection**. This calls the service and fetches a CSRF token to confirm credentials and reachability.
6. **Save.**

## Required Permissions

The SAP user must be authorized, through standard SAP authorizations, to:

- **Call the OData service** on the Gateway (the service must be in the user’s authorized list).
- **Read** the exposed tables — required for a **source** connection.
- **Write** the exposed tables via the service — required for a **target** connection.

Because access is brokered by the ABAP service, table-level permissions are governed by SAP’s own authorization objects rather than by SQL `GRANT` statements. Work with your SAP Basis team to assign a role that covers the service and the tables in scope.

## TLS Configuration

By default the connector validates the Gateway’s TLS certificate against the trust store of the host running the platform (or agent).

For systems with a self-signed or not-yet-trusted certificate, you can disable validation for testing by appending `insecureTls=true` to the service URL:

https://saphost.company.com:44300/sap/opu/odata/sap/ZTDK\_SRV?insecureTls=true

> **WARNING**
> `insecureTls=true` accepts **any** certificate and disables protection against man-in-the-middle attacks. Use it only for testing. For production, install the Gateway’s certificate (or its CA) into the trust store of the host and leave validation enabled.

## Limitations

Because access goes through a curated OData service rather than the database, some behaviour differs from the JDBC connectors:

- **No schema concept.** The service exposes a single, flat namespace. A connection may target **at most one** schema; the tables appear under the synthetic `public` schema. Configuring more than one schema is rejected.
- **Source reads only the exposed tables.** TDK works with exactly the tables the service exposes via `/dbHeaderSet`. Foreign keys that reference non-exposed tables are dropped from the model.
- **No schema (DDL) reproduction.** TDK cannot create or alter tables over OData. The target tables must already exist and be exposed by the service. Schema transfer between a source and an OData target is not supported.
- **Target is write-only.** TDK does not read data back from a target OData connection.
- **Authentication is HTTP Basic only.**
- **OData v2 only**, against the Synthesized service endpoints — generic OData entity sets and `$metadata` discovery are not used.

## Supported Data Types

TDK maps ABAP Dictionary (DDIC) types to its internal types as follows. Unknown types fall back to text (`VARCHAR`) with a warning.

  
| DDIC type | TDK type | Notes |
| --- | --- | --- |
| 
`C`, `N`, `g`

 | 

VARCHAR

 | 

Character, numeric-text, and string fields.

 |
| 

`D`

 | 

DATE

 |  |
| 

`T`

 | 

TIME

 |  |
| 

`P`

 | 

DECIMAL

 | 

Packed number; precision from length, scale from decimals.

 |
| 

`F`

 | 

DOUBLE

 | 

Floating point.

 |
| 

`b`

 | 

TINYINT

 |  |
| 

`s`

 | 

SMALLINT

 |  |
| 

`I`

 | 

INTEGER

 |  |
| 

`8`

 | 

BIGINT

 |  |
| 

`X`, `y`

 | 

VARBINARY

 | 

Raw/byte fields.

 |

## Performance Notes

- **Source connections need a working directory.** TDK materialises read rows into a local mirror (DuckDB) before transforming them; an SAP mirror can be several gigabytes, so make sure the working directory has enough disk space.
- **Reads are paged** at 10,000 rows per request by default; **writes are batched**. Tune `requestTimeoutMs` upward for tables that are slow to page on the Gateway.
- **A failed write batch aborts the run** — TDK does not partially commit a target table.

## Troubleshooting

**Test Connection fails with an HTML/login response**  
The Gateway is redirecting the API call to a login page. Confirm the service is activated and the user is authorized to call it. (TDK already sends `X-Requested-With` to avoid this; persistent redirects usually indicate an authorization or activation problem.)

**Authentication failed (401)**  
Check the username and password. Confirm the user is not locked and is permitted to use the service.

**Forbidden (403) on write**  
Usually a CSRF token issue — TDK refetches and retries automatically. Persistent `403` indicates the user lacks write authorization for the table or the service.

**SSL handshake failed**  
The Gateway certificate is not trusted by the host. Install the certificate (or CA) into the host trust store, or use `insecureTls=true` for testing only.

**Slow reads / timeouts (502 / 503 / 504)**  
The Gateway is slow to page large tables. TDK retries 5xx responses automatically; increase `requestTimeoutMs` if individual pages are timing out.

## Best Practices

- **Use a dedicated SAP service user** with only the authorizations needed for the service and the in-scope tables, and a different user per environment for auditability.
- **Secure credentials** with a secret manager rather than storing plain-text passwords; rotate them periodically.
- **Keep TLS validation on** in production; reserve `insecureTls=true` for testing.
- **Test the connection** before running a workflow, and confirm the user has read (source) or write (target) access to every table in scope.

## See Also

- [SAP HANA Connection](https://docs.synthesized.io/tdk/latest/user_guide/070_integrations/sap/sap_hana) — direct JDBC connection to SAP HANA.
