All endpoints exposed by the Inventory Web (App 2) server. Base URL: http://<host>:4004
Two authentication schemes are used: API Key (upload endpoint, for App 1) and Session Cookie (all other endpoints, for the web UI and SAP item lookup).
Overview
Introduction
The Inventory server exposes three groups of endpoints:
Group
Base path
Auth
Used by
Batch upload
/upload/batch
API Key
App 1 (Windows/scanner)
SAP item/vendor lookup
/items/
Session
Web UI (item search page)
Batch management (OData V4)
/odata/v4/batch/
Session
Web UI, direct OData clients
Overview
Authentication
API Key (upload endpoint)
App 1 must include the key in the x-api-key header.
Keys are configured server-side via the UPLOAD_API_KEYS environment variable
(comma-separated list). Key comparison is constant-time to prevent timing attacks.
# Example header
x-api-key: devkey123
Session Cookie (web & OData endpoints)
Human users authenticate via POST /auth/login (handled by the UI's Login view).
On success, the server sets an inv_sid HttpOnly + SameSite=Strict cookie
with an 8-hour sliding expiry. All subsequent requests must carry this cookie.
Users are configured via the WEB_USERS env var (email:password,...).
💡In development (mocked-auth mode), the session requirement is bypassed. OData endpoints are open. The upload endpoint still requires a valid API key.
Overview
Error format
All custom endpoints return JSON error bodies. OData endpoints follow the OData V4 error format.
{
"error": "Validation failed",
"details": ["idempotencyKey is required", "docType must be one of PO, GRPO, Counting"]
}
Status
Meaning
400
Validation error — see details array
401
Missing or invalid API key / session expired
403
Action not permitted in current batch status
404
Batch or line not found
500
Internal server error
502
SAP B1 Service Layer unreachable or returned an error
Upload
POST /upload/batch
🔑 x-api-key header
Upload a scanned batch from App 1. Idempotent: re-uploading the same
idempotencyKey updates the batch if it is in status Uploaded or Rejected,
and silently ignores the re-upload if the batch is already past review (Approved, Posting, Posted, etc.).
✅App 1 should generate a stable idempotencyKey (e.g. UUID) once per batch session and reuse it for retries. The server guarantees at-most-one batch creation per key.
Request body (JSON)
Field
Type
Req?
Description
idempotencyKey
string
required
Stable unique key for this batch (e.g. UUID). Used for idempotent upsert.
docType
string
required
One of PO, GRPO, Counting
lines
Line[]
required
Non-empty array of scanned lines (see Line schema below)
batchName
string
optional
Human-readable name shown in the web UI
cardCode
string
optional
Vendor BP code (required by SAP for PO/GRPO at posting time)
warehouse
string
optional
Default warehouse code
docRef
string
optional
Business reference from App 1 → written to SAP as NumAtCard (PO/GRPO) or Remarks (Counting)
baseDocRef
string
optional
Base PO DocEntry for GRPO batches
operator
string
optional
Scanner operator name / ID
sourceHost
string
optional
Hostname / site identifier of the uploading App 1 instance
comments
string
optional
Free-text comments
Line object schema
Field
Type
Req?
Description
lineNo
integer
optional
Line sequence number (defaults to index+1)
scannedBarcode
string
optional
Raw barcode value read by the scanner
itemCode
string
optional
SAP item code. If missing → validationStatus = Unresolved
itemName
string
optional
SAP item description (cached from lookup)
quantity
decimal
optional
Scanned quantity
uom
string
optional
Unit of measure
warehouse
string
optional
Line-level warehouse (overrides header warehouse)
batchNumber
string
optional
SAP batch/lot number
serial
string
optional
Serial number
unitPrice
decimal
optional
Unit price (used for PO lines)
scannedBy
string
optional
Operator who scanned this line
scannedAt
datetime
optional
ISO 8601 scan timestamp
source
string
optional
Terminal commID or "import"
validationStatus
string
optional
OK | Unresolved | Warning. Auto-derived from itemCode if omitted.
Searches SAP B1 items by barcode, item code, or description. Proxied server-side to the SAP B1 Service Layer.
Used by the web UI Item Search page. Requires an active session.
Query parameters
Param
Type
Req?
Description
q
string
required
Search term — barcode, item code, or free-text description. Min 2 characters.
Example
GET /items/search?q=widget
Cookie: inv_sid=<session-id>
Full OData V4 CRUD on batches. Base path: /odata/v4/batch/Batches
Common queries
# List all batches (top 20)GET /odata/v4/batch/Batches?$top=20&$orderby=uploadedAt desc
# Filter by status and doc typeGET /odata/v4/batch/Batches?$filter=status eq 'Uploaded' and docType eq 'PO'
# Expand lines in a single requestGET /odata/v4/batch/Batches?$expand=lines
# Get a single batch with linesGET /odata/v4/batch/Batches('<uuid>')?$expand=lines
Key batch fields
Field
Type
Description
ID
Guid
Primary key (UUID)
idempotencyKey
String(100)
Stable upload key from App 1
batchName
String(100)
Human-readable name
docType
PO|GRPO|Counting
Target SAP document type
status
BatchStatus
Lifecycle status (see below)
cardCode
String(50)
Vendor BP code
warehouse
String(20)
Default warehouse
docRef
String(100)
Business reference → SAP NumAtCard/Remarks
sapDocNum
Integer
SAP document number (set after posting)
lastError
String(1000)
Last posting error message
uploadedAt
Timestamp
Upload timestamp
OData V4
Lines entity set
🍪 Session cookie
Scanned lines within a batch. Always accessed via the parent batch expand or directly.
# Lines for a specific batchGET /odata/v4/batch/Lines?$filter=batch_ID eq '<uuid>'# Unresolved lines across all batchesGET /odata/v4/batch/Lines?$filter=validationStatus eq 'Unresolved'
Key line fields
Field
Type
Description
ID
Guid
Primary key
batch_ID
Guid
Parent batch foreign key
lineNo
Integer
Sequence within batch
scannedBarcode
String(100)
Raw barcode
itemCode
String(50)
SAP item code
itemName
String(200)
SAP item description
quantity
Decimal(15,4)
Scanned quantity
validationStatus
OK|Unresolved|Warning
Line validation result
validationMessage
String(255)
Human-readable validation detail
OData V4
Bound Actions
🍪 Session cookie
Custom actions are bound to the Batches entity. Call them via HTTP POST with the batch ID in the URL.
approve — approve a batch for posting
⚠️Approval is blocked if any line has validationStatus = Unresolved. Resolve all lines before approving.
POST /odata/v4/batch/Batches('<uuid>')/inventory.approve
Content-Type: application/json
{ "comment": "Verified by supervisor" }
// Response 200
{ "value": { "status": "Approved" } }
💡Only available when batch status is Approved or PostFailed. The action is idempotent — SAP is checked for a prior document via Comments / Reference2 before creating a new one.
POST /odata/v4/batch/Batches('<uuid>')/inventory.postToSap
Content-Type: application/json
{}
// Response 200 — success
{ "value": { "status": "Posted", "sapDocNum": 1042, "sapDocEntry": 37 } }
// Response 200 — failure (SAP rejected the document)
{ "value": { "status": "PostFailed", "error": "Item ITEM-X does not exist in company db" } }
Reference
Batch status lifecycle
Status
Set by
Meaning
Next states
Uploaded
Upload endpoint
Batch received from App 1, awaiting review
Approved, Rejected, Archived
Approved
approve action
All lines valid; batch cleared for SAP posting
Posting
Posting
postToSap action
SAP API call in progress
Posted, PostFailed
Posted
postToSap action
SAP document created. sapDocNum is set. Batch is locked.
Archived
PostFailed
postToSap action
SAP rejected the document. lastError contains the reason.
Posting (via retry)
Rejected
rejectBatch action
Batch rejected by reviewer. App 1 can re-upload to this key.
Uploaded (via re-upload)
Archived
Manual / future
Batch moved to archive view.
—
Reference
SAP B1 field mapping
How batch/line fields are mapped to SAP B1 document fields when posting.