API Literacy — Foundations

A practical guide to understanding APIs, contracts, and SAP context.

What is an API?

An API (Application Programming Interface) is just a way for two systems to talk to each other. Your phone app talks to a server via API. SAP talks to a bank via API. Even when you log in with Google, that's an API call happening behind the scenes.

You don't need to know what’s inside the system. You just know the “menu” of what it offers. Like in a restaurant — you don't enter the kitchen, you just order “Pizza” and expect pizza back.

API First Mindset

Normally, people build systems first and then later think: “Oh, we also need integration.” That's painful. API First flips it:

You start by asking: what should other people, apps, or systems be able to do with my app? You design the API first — the “contract” — before you write any logic. Then the backend, frontend, and even partners can all work against the same contract. This makes projects faster, cleaner, and easier to integrate.

Example (SAP flavored 🍵):

  • Imagine a coffee producer running SAP S/4HANA.
  • Old style: they’d build a sales order screen, then later add some custom RFCs or IDocs to integrate.
  • API First style: they say “creating a sales order” is an API from the start.
    • Endpoint: /sales-orders
    • Method: POST
    • Input: JSON with customer, product, quantity
    • Output: confirmation number
  • Now mobile apps, web portals, and partner systems all use the same API to create orders. One definition, many consumers.

API Contract — What it Really Means

When we say “API contract,” we mean a formal agreement between provider and consumer on how they communicate. It’s like a legal contract, but for data exchange.

What’s inside an API contract?

  • Endpoints — URLs where the service is available. Example: /sales-orders/{id}
  • Operations (HTTP Methods): GET (read), POST (create), PUT/PATCH (update), DELETE (remove)
  • Request format — data structure the client must send (JSON, XML, OData payload)
  • Response format — what comes back (fields, types, structure)
  • Error handling — how errors look (status codes, error messages)
  • Authentication & authorization — how to prove you’re allowed to call (OAuth, API key, JWT)
  • Performance rules / limits — like pagination, rate limits, batch processing

If the provider changes the contract without notice, everything breaks. That’s why stability and versioning are core principles.

Principles of a Good API Contract

  • Consistency: Same naming, same logic across endpoints. Example: /customers/123/orders not /custOrderData.
  • Predictability: Errors follow a pattern, responses always structured.
  • Discoverability: Clear documentation (OpenAPI, OData metadata).
  • Versioning: Never break old consumers — add /v2/ when needed.
  • Minimalism: Return only what’s needed. Avoid bloated responses.
  • Security: Data protected with HTTPS, OAuth2, role checks.

Operations (CRUD)

Almost every API boils down to CRUD operations:

OperationHTTP MethodExample (Sales Orders)
CreatePOSTPOST /sales-orders → create new order
ReadGETGET /sales-orders/123 → get order details
UpdatePATCH/PUTPATCH /sales-orders/123 → change delivery date
DeleteDELETEDELETE /sales-orders/123 → cancel order

That's the “universal language” across APIs.

OData V4 — The SAP Flavor of API Contracts

OData (Open Data Protocol) is Microsoft-born, SAP-adopted. It's basically REST + conventions. Think of it as a standardized way to describe and query business data over HTTP.

SAP uses it massively in S/4HANA, Fiori, BTP.

Key ideas in OData V4:

  • Entity sets = tables/collections (like SalesOrders).
  • Entities = single record (like SalesOrders('500001')).
  • Metadata document = machine-readable contract ($metadata) describing all entities, fields, relationships, operations.
  • Query options (the real power):
  • $filterGET /SalesOrders?$filter=Customer eq '1000'
  • $select → pick only fields you need
  • $expand → include related entities (like header + items)
  • $orderby, $top, $skip → pagination and sorting

Functions & Actions:

  • Functions = pure, read-only operations (e.g., GetCreditLimit)
  • Actions = side-effect operations (e.g., ReleaseOrder)

Batch requests allow sending multiple operations in one HTTP call, useful in SAP for performance.

Conformance levels: V4 is stricter and lighter than V2 — better JSON, cross-service consistency, async pattern support.

Why it matters in SAP world:

  • Every Fiori app you open is powered by an OData API.
  • Integration on BTP often relies on OData services from S/4.
  • API First with OData means you model business objects as APIs before coding.

So when you hear “API contract in SAP context,” it usually means an OData metadata document ($metadata) plus the CRUD operations exposed on entities.

API Design Process

Think of it like architecture:

  • Identify the business object — Sales Order, Customer, Invoice.
  • Define use cases — create order, change date, get details.
  • Model resources (entities) — /sales-orders, /customers.
  • Assign methods — POST for creation, GET for retrieval, etc.
  • Design request/response formats — which fields, data types, mandatory vs optional.
  • Define errors — if credit check fails, if customer not found, etc.
  • Secure it — authentication (OAuth2), authorization (roles).
  • Versioning strategy — how you’ll handle changes later.

How to Describe APIs

There are standards to make API contracts clear and shareable:

  • OpenAPI (Swagger): The most popular format to describe REST APIs. Machine-readable (YAML/JSON) → generates docs, mock servers, test stubs.
  • OData metadata ($metadata): Auto-generated contract in XML. Lists entities, properties, relationships.
  • AsyncAPI: Like OpenAPI, but for event-driven APIs (Kafka, AMQP, Event Mesh). Important if you go deeper into Event-Driven Architecture (SAP Event Mesh, Kafka).

Design Principles You Must Remember

  • Resource orientation: Think nouns, not verbs (/customers, not /getCustomer).
  • Statelessness: Each request is independent, no hidden state.
  • Error standards: Always return proper HTTP codes (400, 401, 404, 500).
  • Pagination: Never return “all” data; use $skip, $top, or ?page=.
  • Filtering & searching: Use query params ($filter, ?status=open).
  • Extensibility: Allow custom fields without breaking core (SAP uses “extension fields”).

Design Tools & Documentation

  • Stoplight Studio / Swagger Editor — for OpenAPI design.
  • SAP API Business Hub — shows you how SAP describes APIs.
  • Postman — test, mock, share APIs.

API Contracts in Event-Driven Architecture (EDA)

In REST/OData, the contract is about requests and responses. In EDA, the contract is about events and subscriptions.

Think of it as:

  • REST = you call a taxi.
  • Events = you stand outside, and when a taxi becomes available, it honks.

EDA Contract Basics

An EDA API contract usually describes:

  • Event name/topic — e.g., SalesOrder.Created, Customer.Changed.
  • Payload structure — what fields are inside the event (JSON, Avro, etc.).
  • Producer — which system publishes the event.
  • Consumers — who can subscribe.
  • Delivery semantics — at least once, exactly once, etc.
  • Protocol — Kafka, AMQP, MQTT, or SAP Event Mesh.
  • Error handling — what happens if a consumer is down.

How to Describe Event APIs

AsyncAPI is the standard (like OpenAPI, but for events).

AsyncAPI: Sales Order Events
yaml
asyncapi: 2.5.0
info:
  title: Sales Order Events
  version: '1.0.0'
channels:
  sales-order/created:
    subscribe:
      message:
        name: SalesOrderCreated
        payload:
          type: object
          properties:
            id:
              type: string
            customer:
              type: string
            amount:
              type: number

This acts as the contract between publisher (S/4HANA, MDG) and consumer (portal, BTP app, Kafka service).

EDA Design Principles

  • Event as a fact, not a command: Good: SalesOrder.Created describes something that happened. Bad: CreateSalesOrder is a command (belongs in REST API).
  • Schema stability: Never remove fields. Only add optional fields.
  • Decoupling: Producer doesn't know who consumes. Consumer decides what to do.
  • Granularity: Don't flood with tiny events, don't lump everything into “mega events.” Balance matters.
  • Replayability: Events should be durable — you can replay them to rebuild state (Kafka strength).

EDA in SAP Context

  • SAP S/4HANA publishes Business Events (via Enterprise Event Enablement).
  • SAP Event Mesh (BTP service) routes these to consumers (internal apps, partners).
  • SAP Advanced Event Mesh — enterprise-scale (Kafka-like backbone).

Typical examples:

  • BusinessPartner.Changed — MDG publishes when BP master data updated.
  • SalesOrder.Created — order service emits event, warehouse and billing apps react.
  • Material.InventoryLow — triggers replenishment process.

Operations vs Events

REST/OData (Sync)Events/EDA (Async)
Client asks serverServer notifies clients
Request → ResponseEvent → Multiple Consumers
CRUD operationsPublish/Subscribe
Contract: OpenAPI/ODataContract: AsyncAPI/Event Schema

API Contracts Explained

1. REST (synchronous)

👉 Typical for modern apps.

Request (client → server):

REST — Create Order (Request)
http
POST /api/orders
Content-Type: application/json

{
  "customerId": "C123",
  "items": [
    {"productId": "P1", "qty": 2},
    {"productId": "P2", "qty": 1}
  ]
}

Response (server → client):

REST — Create Order (Response)
http
201 Created

{
  "orderId": "O9876",
  "status": "Accepted",
  "total": 120.50,
  "currency": "EUR"
}

Contract (OpenAPI snippet):

OpenAPI — Create Order
yaml
paths:
  /orders:
    post:
      summary: Create a new order
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                customerId:
                  type: string
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      productId: { type: string }
                      qty: { type: integer }
      responses:
        "201":
          description: Order created

2. OData (SAP style, synchronous)

👉 OData = REST + metadata (used in SAP S/4HANA).

Request:

OData — Create Sales Order (Request)
http
POST /sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder
Content-Type: application/json

{
  "SalesOrderType": "OR",
  "SalesOrganization": "1000",
  "DistributionChannel": "10",
  "OrganizationDivision": "00",
  "SoldToParty": "C123",
  "SalesOrderItem": [
    {
      "Material": "P1",
      "RequestedQuantity": "2"
    },
    {
      "Material": "P2",
      "RequestedQuantity": "1"
    }
  ]
}

Response:

OData — Create Sales Order (Response)
json
{
  "SalesOrder": "50000123",
  "OverallDeliveryStatus": "Not Delivered",
  "OverallBillingStatus": "Not Billed"
}

3. SOAP (synchronous or async)

👉 Old enterprise standard, still common in SAP A2A/B2B.

Request (XML):

SOAP — CreateOrder (Request)
xml
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                    xmlns:ord="http://example.com/order">
   <soapenv:Header/>
   <soapenv:Body>
      <ord:CreateOrderRequest>
         <CustomerId>C123</CustomerId>
         <Items>
            <Item>
               <ProductId>P1</ProductId>
               <Quantity>2</Quantity>
            </Item>
            <Item>
               <ProductId>P2</ProductId>
               <Quantity>1</Quantity>
            </Item>
         </Items>
      </ord:CreateOrderRequest>
   </soapenv:Body>
</soapenv:Envelope>

Response (XML):

SOAP — CreateOrder (Response)
xml
<CreateOrderResponse>
   <OrderId>O9876</OrderId>
   <Status>Accepted</Status>
   <Total>120.50</Total>
</CreateOrderResponse>

Contract (WSDL): defines request/response message formats, operations, and endpoints.

4. Async Event (Kafka, EDA)

👉 Fire-and-forget. Client doesn't wait for final result.

Producer (frontend or integration) publishes:

Event — Order.CreateRequested
json
{
  "eventType": "Order.CreateRequested",
  "orderId": "tmp-12345",
  "customerId": "C123",
  "items": [
    {"productId": "P1", "qty": 2},
    {"productId": "P2", "qty": 1}
  ]
}

Consumer (order service) processes, then emits new event:

Event — Order.Created
json
{
  "eventType": "Order.Created",
  "orderId": "O9876",
  "status": "Accepted",
  "total": 120.50
}

Contract (AsyncAPI snippet):

AsyncAPI — Order.CreateRequested (Schema)
yaml
channels:
  order/create:
    publish:
      message:
        payload:
          type: object
          properties:
            customerId: { type: string }
            items:
              type: array
              items:
                type: object
                properties:
                  productId: { type: string }
                  qty: { type: integer }

5. Key takeaway

“An API contract is the agreement: what request looks like, what response or event looks like. For synchronous calls we use REST (OpenAPI) or OData in SAP, sometimes SOAP (WSDL). For asynchronous flows we use event-driven standards like Kafka with AsyncAPI. A simple example is Create Order: frontend sends order details, backend returns orderId and status — and both sides rely on the same contract to avoid breaking.”
About the Author
Dzmitryi Kharlanau

Dzmitryi Kharlanau

Senior SAP Consultant·EPAM Systems

Senior SAP SD / O2C Consultant | S/4HANA Logistics | Integration at EPAM Systems. Interested in S/4HANA, automation, AI, and Event-Driven Architecture (EDA).

SAP SDOrder-to-CashS/4HANABTPEDAIntegrationAutomationAI