Warehouse management inbound API stock posting creates mismatched inventory quantities

We’re experiencing inventory quantity mismatches when posting inbound deliveries through the Warehouse Management OData API. Our external WMS system sends goods receipt confirmations, but occasionally we see duplicate stock postings or missing quantities in SAP.

Example API call:


POST /API_INBOUND_DELIVERY_SRV/A_InbDeliveryItem
{"DeliveryDocument": "800012345",
 "Material": "MAT-12345",
 "ActualDeliveryQuantity": "100"}

When network issues cause retries, we sometimes get double postings (200 units instead of 100). Other times, the API returns 201 Created but the stock doesn’t update in transaction MIGO. We’re not implementing idempotency keys currently, and I’m unclear whether we should use synchronous or asynchronous processing for these stock movements. The transaction consistency between the delivery document and inventory posting seems unreliable. How do others handle reliable stock posting through APIs while avoiding duplicate entries and ensuring validation?

Your inventory mismatch issues stem from three interconnected problems that need to be addressed together. Here’s the comprehensive solution:

1. Implement Idempotency Key Pattern

Generate a unique idempotency key for each stock posting operation:


X-Idempotency-Key: DEL800012345-ITM10-TS20250508143022

Structure: DeliveryDocument + ItemNumber + Timestamp. Store processed keys in a custom Z-table (ZIDEMPOTENCY_LOG) with fields:

  • IDEMPOTENCY_KEY (primary key)
  • MATERIAL_DOCUMENT (result reference)
  • CREATED_AT (timestamp)
  • STATUS (SUCCESS/FAILED)
  • RESPONSE_PAYLOAD (JSON of original response)

In your API implementation (custom ABAP class or OData service), check this table before processing:

  • If key exists and STATUS = SUCCESS: Return stored response (HTTP 200 with original result)
  • If key exists and STATUS = FAILED: Allow retry with same key
  • If key doesn’t exist: Process normally and store result

This prevents duplicate postings during network retries while maintaining idempotent behavior.

2. Ensure Transaction Consistency

Your current approach updates the delivery item but doesn’t guarantee the material document posts. Use the complete posting flow:


POST /API_INBOUND_DELIVERY_SRV/PostGoodsReceipt
Content-Type: application/json
X-Idempotency-Key: DEL800012345-ITM10-TS20250508143022

{"DeliveryDocument": "800012345",
 "GoodsMovementCode": "01",
 "Items": [{"DeliveryDocumentItem": "10",
   "QuantityInEntryUnit": "100",
   "EntryUnit": "EA"}]}

This endpoint handles both delivery confirmation AND material document creation atomically. If either fails, both rollback. Verify the response includes:

  • MaterialDocument number (confirms inventory posting)
  • MaterialDocumentYear
  • DeliveryDocument (confirms delivery update)

If MaterialDocument is empty in the response despite HTTP 201, the posting failed.

3. Choose Synchronous vs Asynchronous Processing

For stock postings, use synchronous processing because:

  • Immediate feedback on posting success/failure
  • WMS can retry failed postings immediately
  • Inventory accuracy is critical for downstream operations
  • Transaction consistency is guaranteed within the HTTP request

Asynchronous processing is only appropriate for:

  • Bulk inventory uploads (100+ line items)
  • Non-critical updates (delivery note text, tracking numbers)
  • Operations that can tolerate eventual consistency

For your inbound delivery scenario, synchronous is the right choice.

4. Implement Stock Posting Validation

After each successful API call, validate the posting:

a) Check material document created:


GET /API_MATERIAL_DOCUMENT_SRV/A_MaterialDocumentHeader('4900012345')

Verify DocumentDate, PostingDate, and GoodsMovementCode match your request.

b) Verify inventory quantities:


GET /API_WAREHOUSE_STOCK_SRV/A_WhseStorageBinStock
  ?$filter=Material eq 'MAT-12345'
    and Warehouse eq 'WH01'
    and StorageBin eq 'BIN-001'

Confirm AvailableStock increased by expected quantity.

c) Reconciliation check in your WMS:

  • Store the MaterialDocument number returned from SAP
  • Periodically query SAP stock levels and compare to WMS quantities
  • Flag discrepancies for manual investigation

Implementation Pattern:


// Pseudocode for reliable stock posting:
1. Generate idempotency key from delivery+item+timestamp
2. Check ZIDEMPOTENCY_LOG table for existing key
3. If exists and successful: return cached response
4. Build PostGoodsReceipt payload with delivery and movement data
5. Call synchronous API with idempotency header
6. Parse response - verify MaterialDocument field populated
7. If MaterialDocument exists: log success + store response
8. If MaterialDocument empty: log failure + throw error
9. Return MaterialDocument number to WMS for reconciliation

Additional Safeguards:

  • Set HTTP timeout to 60 seconds (stock posting should complete quickly)
  • Implement exponential backoff for retries (1s, 2s, 4s intervals)
  • Log all API requests/responses to custom Z-table for audit trail
  • Enable SAP Application Interface Framework (AIF) for monitoring if available
  • Schedule daily reconciliation job comparing WMS vs SAP stock quantities

By combining idempotency keys (prevents duplicates), synchronous processing (ensures consistency), transaction validation (confirms posting), and reconciliation (catches edge cases), you’ll eliminate the inventory mismatches. The idempotency table is crucial - it makes your API truly retry-safe while maintaining exactly-once semantics for stock movements.


This draft is based on general SAP S/4HANA knowledge. It has not been verified against your specific version and environment. Practitioners: verify the steps and share your experience below.

Your duplicate posting issue is classic lack of idempotency. Add a unique idempotency key header to each request (like a UUID based on delivery+item+timestamp). The API should check if that key was already processed and return the existing result instead of creating a new posting.

Tested this on S/4HANA 2023 FPS01, and implementing the idempotency key pattern with ZIDEMPOTENCY_LOG table eliminated duplicate material documents from retry storms on inbound delivery postings.

The 201 Created with no stock update suggests your API call is succeeding at the delivery level but failing at the material document posting level. Check if you’re using the correct API endpoint - you might need to call the GoodsMovement API directly instead of just updating the delivery item. Also verify that your material master has proper warehouse management views configured in transaction MM03. Missing WM data can cause silent failures where the delivery updates but inventory doesn’t move.

You need to decide between sync and async based on your business requirements. For inbound deliveries, I recommend synchronous processing so you get immediate confirmation of stock posting success or failure. This lets your WMS know right away if there’s a problem. Async processing is better for bulk operations or when you can tolerate eventual consistency.

Implement proper error handling and check the response messages carefully. SAP APIs often return 201 Created even when backend validation fails - you need to parse the response body for error messages. Look for fields like ‘Type’: ‘E’ in the message array. Also enable transaction ST22 dumps and SM21 system logs to track what’s happening when the stock doesn’t update despite a successful HTTP response.

Check if your API implementation uses BAPI_GOODSMVT_CREATE or a custom function module. If it’s BAPI-based, you must call BAPI_TRANSACTION_COMMIT after the goods movement call, otherwise the changes aren’t persisted to the database. This would explain why you get 201 Created but no actual stock update. The API should handle this automatically, but custom implementations sometimes miss the commit.