How-toSAP S/4HANA / ECCAPIs / Python

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

Question
api sap python

Also searched as

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

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.

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

How to call SAP OData from Python

  1. 1Confirm the service is active and reachable, ideally by a browser or /IWFND/GW_CLIENT test, and note the base URL and the sap-client.
  2. 2Create a technical SAP user with a role limited to the service. Store credentials in environment variables or a secrets store, never in code.
  3. 3Use a requests Session so cookies and the CSRF token persist across calls.
  4. 4GET with params: $top, $select, $filter and $format=json. Reduce columns early; SAP payloads get large quickly.
  5. 5Read the results from d.results for OData V2 (or value for V4) and follow d.__next (V2) or @odata.nextLink (V4) to page.
  6. 6For 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.
  7. 7Handle 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.
  8. 8Add timeouts to every call, log the request path and duration, and keep the user's TLS verification on.

A minimal read

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.

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

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.

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

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

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.

Try it here, free

Paginated OData Fetch Loop Python Generator

Open full tool

Build a Python loop that follows nextLink pages from an OData entity set and writes the result to CSV with a hard row cap.

Common 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.

How an ERP-grounded AI assistant handles this

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.

Frequently asked questions

How do I call a SAP API from Python?

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?

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?

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?

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.

Related

How-to

SAP S/4HANA API Guide: Business Hub, OData, Public Cloud and Business Partner

S/4HANA APIs are discovered in the SAP Business Accelerator Hub and mostly delivered as A2X OData services such as API_BUSINESS_PARTNER. On-premise you activate them in the Gateway; in the public cloud you create a communication user, system and arrangement for a communication scenario. PI/PO or Integration Suite sit in between for orchestration, and SAP Digital Manufacturing has its own APIs on BTP.

How-to

SAP PP, PM and MM API: Production Orders, Maintenance Orders and Material Master

S/4HANA exposes production orders, maintenance orders and material master through OData services published in the SAP Business Accelerator Hub, for example API_PRODUCTION_ORDER_2_SRV, API_MAINTENANCEORDER and API_PRODUCT_SRV. On ECC or older releases, use BAPIs and RFC such as BAPI_PRODORD_CREATE, BAPI_ALM_ORDER_MAINTAIN and BAPI_MATERIAL_SAVEDATA. Direct M-table access is not an API and is best avoided.

How-to

How to Use BAPI_TRANSACTION_COMMIT Correctly

SAP's BAPI programming model separates business logic from the database commit on purpose, so a caller must explicitly call BAPI_TRANSACTION_COMMIT after a successful BAPI - usually with WAIT = 'X' - or the created object never actually persists. Skipping this step, or forgetting WAIT, is the most common reason a BAPI 'runs fine' but nothing gets saved.

Error fix

SAP M7 021: Deficit of SL Stock Quantity

M7 021 fires during a goods issue, delivery, or confirmation when SAP checks the unrestricted-use (SL) stock for the exact plant, storage location and batch combination and finds less than what you are trying to post out. Fix the entry (batch, storage location, quantity) first; only enable negative stock or downgrade the message to a warning if the business genuinely needs to post ahead of a receipt.

Error fix

SAP IDoc Status 51: Application Document Not Posted

Status 51 tells you the IDoc reached the application layer and failed to post, but the status text itself is not the error - the real cause sits in the status record's long text or the linked application log. Fix the underlying data or configuration, then reprocess the IDoc through BD87 rather than editing the status.

Error fix

SAP Short Dump TIME_OUT: Maximum Runtime Exceeded

A TIME_OUT runtime error means a dialog (or RFC) work process ran longer than the maximum allowed runtime, controlled by profile parameter rdisp/max_wprun_time (600 seconds by default). The fix is almost always to move the long-running work to background processing or tune the underlying program, not to raise the timeout.

AI for ERP

AI for SAP S/4HANA, Running On-Prem or in Your Private Cloud

Run AI on SAP S/4HANA without sending ERP data to a public API. On-prem and private-cloud architecture, CDS views, OData, and honest deployment trade-offs.

AI for ERP

SAP BTP and a Private LLM: Where the Generative AI Hub Fits and Where It Doesn't

Where SAP BTP's Generative AI Hub fits and where a self-hosted LLM belongs instead. CAP, Integration Suite, and an architecture decision framework.

Stuck on SAP S/4HANA / ECC?

Talk to engineers who work inside SAP S/4HANA / ECC every week, and who build private AI that answers these questions from your own ERP data.

Keep exploring

Free tools

ERP fixes and how-tos

Runs with your ERP

AI on your ERP

Integrations

Software