# Calling SAP APIs from Python: OData with requests, Authentication and PyRFC

> Source: https://netray.co/erp-help/sap-api-python-odata-requests-pyrfc-authentication-pagination
> Publisher: Netray (netray.co), AI and integration engineering for ERP and manufacturing systems.
> Section: ERP Help

## Short answer

The simplest way to call SAP from Python is OData over HTTPS with the requests library: send a GET to the service with $select, $filter and $top, authenticate with basic or OAuth, and follow the next-page link. For writes fetch a CSRF token first. Use PyRFC only for functions that have no OData service, and accept the extra SAP NW RFC SDK dependency.

## Kind

how-to

## System

sap

## Erp

SAP S/4HANA / ECC

## Module

APIs / Python

## Query

api sap python

## Alternate Queries

- call SAP OData from Python
- python requests SAP odata example
- pyrfc SAP RFC call python
- SAP odata csrf token python

## Applies To

SAP S/4HANA and ECC with OData V2 or V4 services activated. Python 3.9 or later.

## Steps

### How to call SAP OData from Python

**Items:**

- Confirm the service is active and reachable, ideally by a browser or /IWFND/GW_CLIENT test, and note the base URL and the sap-client.
- Create a technical SAP user with a role limited to the service. Store credentials in environment variables or a secrets store, never in code.
- Use a requests Session so cookies and the CSRF token persist across calls.
- GET with params: $top, $select, $filter and $format=json. Reduce columns early; SAP payloads get large quickly.
- Read the results from d.results for OData V2 (or value for V4) and follow d.__next (V2) or @odata.nextLink (V4) to page.
- For POST, PATCH or DELETE, first GET with the header x-csrf-token: Fetch, read the token from the response header, then send it back with the same session.
- Handle errors: read the error.message.value text in the JSON body, retry on 502/503/429 with backoff, and do not retry writes without an idempotency check.
- Add timeouts to every call, log the request path and duration, and keep the user's TLS verification on.

## Sections

### A minimal read

**Body:**

This example reads a few products and follows paging. It uses basic authentication for brevity; in production prefer OAuth client credentials or certificates where the system supports them.

**Code:**

import os, requests

BASE = 'https://sap.example.com:44300/sap/opu/odata/sap/API_PRODUCT_SRV'
s = requests.Session()
s.auth = (os.environ['SAP_USER'], os.environ['SAP_PASS'])
s.headers.update({'Accept': 'application/json', 'sap-client': '100'})

url = BASE + '/A_Product'
params = {'$top': 100, '$select': 'Product,ProductType,BaseUnit'}
while url:
    r = s.get(url, params=params, timeout=30)
    r.raise_for_status()
    data = r.json()['d']
    for row in data['results']:
        print(row['Product'], row['ProductType'])
    url = data.get('__next')
    params = None

### Writes and the CSRF token

**Body:**

SAP Gateway protects changes with a cross-site request token. Send a GET with x-csrf-token set to Fetch, read the x-csrf-token response header and send it on the next call with the same session. If you get 403 with a message about the token, the session cookie or token was not reused.

For PATCH use the If-Match header with the ETag from the read when the service supports it, to avoid overwriting a concurrent change.

**Code:**

r = s.get(BASE + '/', headers={'x-csrf-token': 'Fetch'})
token = r.headers['x-csrf-token']
r = s.patch(BASE + "/A_Product('TG11')", json={'GrossWeight': '1.2'}, headers={'x-csrf-token': token, 'If-Match': '*'})
r.raise_for_status()

### PyRFC and the RFC route

**Body:**

PyRFC wraps the SAP NetWeaver RFC SDK so Python can call function modules and BAPIs directly, for example a BAPI that has no OData service. You must obtain the SDK from SAP under your licence, and the library has had maintenance changes, so check its current status before depending on it.

RFC reaches the SAP system on its gateway port, which is a different network path from HTTPS, so involve your network and Basis teams early. After a BAPI that changes data, call BAPI_TRANSACTION_COMMIT.

### Data science and bulk work

**Body:**

For analysis, pull only the columns you need with $select and filter on dates in the server. For very large extracts, use a proper extraction route rather than paging OData for hours, and run it outside business hours.

## Pitfalls

- Hard-coding credentials in a script or notebook.
- Not using a Session, so the CSRF token fails on the next call.
- Paging without a stable sort, causing missed or duplicate rows.
- Disabling TLS verification to get past a certificate error.
- Depending on PyRFC without checking SDK licensing and project status.

## Ai Angle

A script like this is the plumbing behind most AI use of SAP. Netray's connectors do the same job with roles enforced, a read-only default and the query shown to the user. In an on-prem deployment the Python or service layer, the model and SAP all stay inside your network.

## Faq

### How do I call a SAP API from Python?

**Answer:** Use the requests library against an activated OData service: authenticate, send GET with $select and $filter, parse the JSON from the d object and follow the next link for paging. For writes, fetch a CSRF token first and reuse the session.

### Why do I get 403 on a POST to SAP OData?

**Answer:** Most often the CSRF token is missing or was fetched in a different session. Send a GET with x-csrf-token: Fetch first, then use the returned token and the same cookies on the change request.

### Should I use PyRFC or OData?

**Answer:** Prefer OData over HTTPS where a service exists: simpler, easier to secure and throttle. Use PyRFC when you need a function module or BAPI with no service, accepting the SAP NW RFC SDK dependency.

### How do I page through large SAP OData results?

**Answer:** Read the next-page link in the response, d.__next for OData V2 or @odata.nextLink for V4, and keep calling it until it is empty. Add a sensible page size with $top and select only the needed columns.

## Search terms

api sap python, sap odata python, python requests sap, pyrfc sap, sap api python example, sap odata csrf token, call sap from python, sap rest api python

---
Talk to an engineer: https://netray.co/contact?intent=erp_ai | Machine catalog: https://netray.co/agent/catalog.json
