SAP Business One runs thousands of mid-sized companies. Sooner or later it has to talk to an online store, a CRM, a sales app or a customer portal. The recommended way is Service Layer, SAP B1’s official web API: OData over HTTPS, usually at https://<server>:50000/b1s/v1/. It enforces SAP B1 business rules, so it is far safer than writing to the database (which you should never do).
1. Log in
const base = 'https://sap-server:50000/b1s/v1';
const r = await fetch(`${base}/Login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ CompanyDB: 'SBO_COMPANY', UserName: 'integration', Password: process.env.SAP_PASS }),
});
const cookies = r.headers.getSetCookie().map((c) => c.split(';')[0]).join('; ');
Sessions expire after inactivity (around 30 minutes by default): reuse them and log in again on 401. Use a dedicated integration user with minimal permissions.
2. Query with OData
GET /b1s/v1/Items?$select=ItemCode,ItemName,QuantityOnStock&$filter=Valid eq 'tYES'&$orderby=ItemCode
Service Layer returns small pages by default plus an odata.nextLink. Ask for bigger pages with Prefer: odata.maxpagesize=200 and follow nextLink until it disappears.
3. Create an order
await fetch(`${base}/Orders`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Cookie: cookies },
body: JSON.stringify({
CardCode: 'C0001',
DocDueDate: '2026-10-05',
NumAtCard: 'WEB-10492',
DocumentLines: [{ ItemCode: 'A001', Quantity: 2, UnitPrice: 350 }],
}),
});
Store your external reference (e.g. NumAtCard) and look it up before creating, so retries never duplicate orders.
Best practices
Never write directly to the database; make writes idempotent; queue and retry on failures; log every call; configure certificates properly instead of disabling validation; and POST /Logout in batch jobs.
Need SAP Business One connected to another system? Let’s talk.