IT CanvassTalk to an advisor
SAP APIs · LessonReviewed by Ravi M, SAP Trainer, 10 yrs · Updated · Published · SAP S/4HANA 2023 · all levels

SAP REST API

REST/OData is the modern way to access SAP over HTTP with JSON, the interface behind Fiori and most cloud and web integrations. In SAP, "REST API" in practice usually means OData services.

Quick answer

SAP's REST interface is OData: JSON over HTTP with $filter, $select, $expand, $orderby, $top and $skip, exposed by S/4HANA and the cloud products and buildable from CDS. Authenticate with OAuth rather than basic where anything faces outward, fetch the metadata first, then read, then write. Most of an integration is deciding which failures retry and where a failed message goes.

Key takeaways
  • In SAP, "REST API" in practice usually means OData services.
  • Watch out: Over-fetching without $filter/$select/$top.

REST and OData in SAP

SAP’s primary RESTful interface is OData, a standardised REST protocol returning JSON, with rich query options. OData services expose SAP business data and operations to Fiori, mobile apps, and external systems. S/4HANA and cloud products publish many OData APIs (on the Business Accelerator Hub), and you can build your own from CDS.

Worth stating plainly for anyone coming from general web development: SAP's REST is mostly OData rather than bespoke REST. That is a constraint and an advantage. The constraint is that URL conventions are prescribed. The advantage is that every service is self-describing and every client library already knows how to page, filter and navigate.

A REST/OData call

GET /sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder?$filter=SoldToParty eq '1000'&$top=20
Authorization: Bearer <token>
Accept: application/json

Query options

OData supports $filter, $select, $expand, $orderby and paging ($top/$skip), so clients fetch exactly what they need. This precision keeps integrations efficient, request minimal data rather than pulling everything and filtering client-side.

Authenticating a call, which is where most integrations stall

Getting a response requires being allowed to ask, and the options differ enough to be worth knowing before designing.

Basic authentication sends a username and password on every call. It works, it is simple, and it means a credential sits in the calling system's configuration and rarely rotates. Fine inside a network, weak facing outward.

OAuth exchanges a client identifier and secret for a short-lived access token, then sends the token. Better, because the credential that travels expires, and it is the standard for cloud products and anything reached across the internet.

Certificate based authentication uses a client certificate rather than a secret, which removes the password entirely and moves the problem to certificate expiry, which is its own recurring incident.

Principal propagation passes the calling user's identity through to the backend, so authorisation applies per user rather than to a shared technical account. That is the right answer when individual users are calling, and it is more setup.

Two practical points. A technical user for an interface should hold exactly the authorisations that interface needs, and it frequently holds far more because somebody granted access to make it work. And whichever mechanism, a write call needs its CSRF token fetched first, which is the error people meet before they meet anything else.

Read, then write

Half an hour, and it covers the sequence every integration performs.

  1. Call a service's metadata document with basic authentication. If it returns, connectivity and credentials are proven and nothing else is.
  2. Read a collection with $top=5. Confirm the shape matches the metadata.
  3. Add $filter and $select. Note the response is smaller and, if the service is CDS-based, that the filter reached the database.
  4. Fetch a CSRF token with a GET, sending the fetch header.
  5. Post a new record with that token and the session cookie. Read the response carefully.
  6. Deliberately post something invalid and read the error. A well-built service returns a message you can act on; a poor one returns a five hundred.

Step six is the one worth doing on any API you are about to depend on, because error handling is what you will spend your time on later.

When to use it

Prefer REST/OData for UIs, mobile, and modern web integrations, and whenever you consume S/4HANA cloud APIs. It is the strategic direction; reserve SOAP and RFC for classic or SAP-to-SAP scenarios.

And what to use instead when it does not fit. High volume asynchronous document exchange belongs on IDoc rather than on repeated synchronous calls. A remote function call to existing ABAP logic is RFC. And a supported operation on a business object with its own validation is often a BAPI rather than something to rebuild.

Error handling, which is most of an integration

The happy path takes an afternoon. What the integration does when something fails is the design, and it is worth deciding rather than discovering.

Distinguish the failure classes. A network timeout is transient and should be retried. A four hundred means the request was wrong and retrying it will fail identically forever. A four hundred and one is authentication. A four hundred and three is authorisation, which is a different fix. A four hundred and twenty-nine is rate limiting and should be retried after a delay. A five hundred is the far end's problem and may or may not be transient.

Retry only what is safe. Whether resending a create produces a second record depends on whether the service is idempotent, and if it is not, retrying is worse than failing.

Back off. Immediate retries against a struggling service make it worse. Exponential backoff with a cap is the standard answer.

Give up somewhere. After a defined number of attempts the message goes to a place a person will look, with enough context to act.

Log the correlation. A request identifier carried through both systems is what turns "it failed sometime yesterday" into a specific record.

None of this is SAP-specific and all of it is what separates an interface that runs for years from one somebody babysits.

The decisions on an integration

  • Who calls whom. SAP calling out, or something calling in. Inbound means exposing and securing a service; outbound means SAP holding credentials for somebody else.
  • Batch or single. Batching reduces round trips and complicates error handling, because part of a batch can fail.
  • Where the state lives. If the integration has to know what it has already sent, something must remember, and deciding where is a design question people postpone until the first duplicate.
  • How it is monitored. An interface without an alert on failure is discovered by a user, which is always later and more expensive.

Testing an integration before it is live

Integrations are tested badly more often than they are built badly, and the gaps are predictable.

Use real payloads. Get a message the sending system actually produces rather than one composed from the specification. The difference between the two is where most defects live.

Test the failures deliberately. A missing mandatory field, a value too long, an unexpected character set, a duplicate, a reference to something that does not exist. Each should produce a diagnosable outcome rather than a silent one.

Test the far end being down. Stop the target and send. What happens should be a decision rather than a discovery.

Test volume. Something that works on ten messages can behave differently on ten thousand, particularly where paging or batching is involved.

Test the retry. Send the same message twice deliberately and confirm the outcome is what you intended.

The last one is the one skipped most often and it is the one that produces duplicate orders in production, which is the incident nobody forgets.

Common pitfalls

  • Over-fetching without $filter/$select/$top.
  • Ignoring OData error handling.
  • Using RFC/SOAP where OData fits better.
  • No retry policy, or one that is not safe. Whether resending a create produces two records is a design question, and finding out in production is the expensive answer.
  • Credentials in code rather than in a secure store. They then travel with every transport and appear in every environment.
  • Ignoring the error body. See the API reference for what is available.
  • Treating every non-200 the same. A four hundred will fail identically forever and a five hundred may not, and retrying both the same way wastes effort on one and gives up on the other.
  • No correlation identifier. Diagnosing across two systems without one is guesswork.

Where this goes next

Making a call is the easy half, and building an integration with authentication, paging, retries and error handling that survives real traffic is the part you do in the course.

The part worth designing before writing any code is what happens when a call fails. Which failures retry, how many times, with what backoff, and where a message goes when it finally does not work.

Already working on SAP and stuck on a live ticket?Get an expert SAP developer on screen-share to finish your daily tasks with you. Deliver on time, protect your reputation and your job. Monthly support only, no task-wise plans.Task assigned · no idea where to startStill stuck · your job on the lineExpert joins your screenDelivered on timeExplore On Job Support