8 min read Adir Cohen
Integrating a B2B ordering platform with SAP Business One: architecture notes
How to connect a B2B ordering platform to SAP Business One via the Service Layer: sessions, paging, pricing, stock, idempotent orders and monitoring.
A B2B ordering platform delivers value when orders flow straight into the ERP, with the right customer, the right price and stock that actually exists. When the SAP Business One integration is unreliable, the platform becomes one more inbox: someone in the office re-keys orders, fixes prices and calls customers about items that were never available.
These notes draw on hands-on experience: since 2016, AC's founder has led the development of a multi-tenant B2B platform with ERP integrations to Priority, SAP Business One and other systems. They cover the decisions that matter most when the target is SAP Business One. Rather than a tutorial on every endpoint, they map where these projects usually succeed or fail.
Choose the integration surface
SAP Business One offers more than one way in, and the choice shapes everything else:
- Service Layer is an HTTP/OData API that sits on top of the same business-object core as the DI API.
/b1s/v1speaks OData v3 and/b1s/v2speaks OData v4. It works from any language with an HTTP client, which makes it the natural fit for a web platform. - DI API is the older SDK. It is still useful for objects or behaviors the Service Layer does not expose, but it ties you to a Windows host and a COM-based client.
- The Integration Framework (B1if) is a middleware layer inside the SAP ecosystem. It fits when a partner already runs scenarios there, less so when you own the platform side.
For a B2B ordering platform, the Service Layer is our default. Before committing, check the metadata of your exact version to confirm that every object you need is there, and keep the DI API as a fallback for the gaps.
Sketch the data flows first
Most integration problems are really scope problems. Write down what moves, in which direction and how often, before writing code:
| Data | Direction | Typical cadence |
|---|---|---|
| Business partners and contacts | SAP B1 to platform | Every few minutes, incremental |
| Items, groups, units of measure | SAP B1 to platform | Every few minutes to hourly |
| Price lists and special prices | SAP B1 to platform | As often as pricing changes |
| Stock per warehouse | SAP B1 to platform | Frequently, plus a check at checkout |
| Sales orders | Platform to SAP B1 | Immediately, through a queue |
| Order status, deliveries, invoices | SAP B1 to platform | Every few minutes |
The rule we follow: SAP Business One is the source of truth for customers, items, prices and stock. The platform keeps a local copy so it can be fast, and writes back only the documents it owns, which is almost always sales orders.
Treat Service Layer sessions as a resource
The Service Layer is session-based. You POST /Login with the company database, user name and password, and get back a session cookie (B1SESSION) and, behind a load balancer, a ROUTEID cookie that pins you to one node. Sessions expire after a period of inactivity, 30 minutes by default.
A common mistake is logging in for every request. It is slow, and it leaves a large number of open sessions on the server. A better pattern:
- Keep a small pool of logged-in sessions in the integration service, with both cookies.
- Reuse them across requests, and refresh before they expire.
- On a
401, log in again once and retry the request; if it fails again, stop and alert. - Use a dedicated integration user with only the permissions it needs, so its activity is easy to trace and easy to revoke.
None of this ever runs in the browser. The platform talks to its own backend, and only the backend talks to SAP.
Read master data efficiently
Pulling master data is the bulk of the traffic, so it pays to be precise:
- Ask only for what you use.
$selectthe fields the platform shows and$filterout inactive items or blocked partners. - Page properly. The Service Layer returns results in pages (20 records by default). Follow the
odata.nextLinkthe response gives you, and raise the page size with thePrefer: odata.maxpagesizeheader rather than fetching everything at once. - Sync incrementally. Items and business partners carry update date and time fields. Pull what changed since the last run, and run a full reconciliation nightly as a safety net.
- Store, then serve. The platform reads from its own database. If SAP is down for maintenance, customers can still browse and place orders.
Pricing is the hard part
Prices in SAP Business One can come from several layers: the price list attached to the business partner, special prices for that partner, period and volume discounts, and discount groups. A B2B customer expects to see exactly the price that will appear on the order.
There are two workable approaches:
- Replicate the rules. Sync price lists, special prices and discount definitions, and compute the price in the platform. It is flexible and fast, but every rule SAP applies has to be reproduced faithfully.
- Materialize the result. Compute or fetch the final price per customer and item, and store it. It is simpler and avoids drift, at the cost of more data to sync.
Whichever you choose, verify it. A small job that compares the platform's price with the price SAP puts on a test document catches drift long before a customer does.
Stock: be honest about availability
Per-warehouse stock is available on the item, through its warehouse information collection: in stock, committed and ordered quantities. A common definition of "available" is in stock minus committed, with ordered quantities shown as incoming. Decide with the business which warehouses count for which customers, and whether the platform shows exact numbers or a simpler in-stock indicator. Then re-check availability at checkout, because a cached number from ten minutes ago can be wrong.
Post orders idempotently
Creating a sales order is a single request with the header and its lines:
POST /b1s/v2/Orders
{
"CardCode": "C20000",
"DocDueDate": "2026-11-01",
"NumAtCard": "WEB-104233",
"DocumentLines": [
{ "ItemCode": "A1001", "Quantity": 12, "WarehouseCode": "01" },
{ "ItemCode": "B2002", "Quantity": 3, "WarehouseCode": "01" }
]
}
The hard part is not the request itself, but what happens when the response never arrives. The order may have been created in SAP even though your side saw a timeout. Retrying blindly creates a duplicate.
The fix is to make posting safe to repeat:
- Save the order in the platform first, with its own unique reference, and put it in an outbound queue.
- Send that reference with the document, in the customer reference field or in a dedicated user-defined field.
- Before any retry, query SAP for a document with that reference. If it exists, record the
DocEntryand stop.
If the business wants orders reviewed before they become real documents, post them as drafts and let SAP's own approval procedures take over. When several operations must succeed or fail together, the Service Layer's $batch endpoint supports change sets that are applied as a single unit.
Make failures visible
An integration is only as good as how quickly you learn that something has failed:
- Separate retryable from final errors. Timeouts and server errors deserve a retry with backoff. A business-rule rejection, such as a frozen customer or an inactive item, will not fix itself and should reach a person with the full error message.
- Give operations a screen. A list of stuck orders, the reason for each and a resend button after the cause is fixed saves a lot of phone calls.
- Alert on silence. If no order has reached SAP during business hours for a few hours, something is probably stuck.
- Log every exchange. Request, response, duration and the document number created. When someone asks "where is my order?", the answer should take seconds.
A short pre-launch checklist
- Service Layer confirmed for every object you need on your version, DI API fallback identified.
- Dedicated integration user with minimal permissions.
- A test company database with realistic data.
- An agreed sync table: what, which direction, how often.
- Session pooling, re-login on
401, and no SAP calls from the browser. - Incremental sync plus a nightly full reconciliation.
- Idempotent order posting with a unique external reference.
- A price verification job and an availability check at checkout.
- An admin view for failed documents, and alerts.
Closing thoughts
A good SAP Business One integration is boring in the best sense: orders arrive with the right prices, stock is believable and nobody re-keys anything. Getting there is mostly about architecture choices made early: SAP as the source of truth, a separate integration layer, and an order pipeline that survives network failures.
If you are planning a platform like this, read more about the ERP integrations we build at AC, or get in touch. Hebrew readers may also find our practical guide to connecting a B2B site to Priority useful.
Sources
- SAP Business One Service Layer API Reference — official SAP reference
- SAP Business One documentation — SAP Help Portal