WineWorld.lk Commerce Platform | Business Central Inventory Interface (0.1-draft)

Download OpenAPI specification:

Inventory Movement API and Snapshot API received by the WineWorld.lk website from Dynamics 365 Business Central.

Document control

Item Value
Project WineWorld.lk Commerce Platform
Document Business Central Integration - Inventory Interface (OpenAPI 3.1)
Reference 26-WW-WD-042
Version 0.1 (draft for review), 26 October 2026
Governing document Business Central Integration - API Specification v0.1. This file is the machine-readable form of its Sections 4 and 5 and Annexes A and B. Where the two differ, the governing document prevails until the next issue aligns them.
Prepared by Encyte
Prepared for Wine World (WW) and the Business Central implementation team
Status For review. Values marked [to confirm] are to be confirmed by the party named. Limits marked [proposed default] are confirmed once the transaction volumes are provided.

Division of responsibility

The website is the receiving system for inventory movements, so the two interfaces in this document (the Inventory Movement API and the Snapshot API) are defined by Encyte and implemented on the website. The sales order interface runs in the opposite direction: Business Central is the system of record for items, locations, tender codes, posting rules and the POS transaction, so that API contract is to be authored and owned by the Business Central team. The website will conform to the contract the Business Central team publishes. The attribute list and processing scenarios the website requires of it are in Section 7 of the governing document and are deliberately not expressed here.

Principles

  • Store, then acknowledge. Every structurally valid movement is written to a durable event store before HTTP 200 is returned. A 200 means the website holds the data; Business Central does not retransmit it.
  • Idempotent by key. The duplicate key is (sourceSystem, eventRef). A retransmitted movement is acknowledged as duplicate and is not applied a second time.
  • Signed quantities. A negative quantity reduces website availability, a positive quantity increases it. Sales and returns may share one payload.
  • Processing is decoupled from receipt. Movements are applied by a background process, sequentially per location and in parallel across locations.
  • The website never deducts twice for its own orders. A WEB_ORDER_POST movement carrying websiteOrderRef releases the website's own reservation for that order as it is applied.
  • Unknown is not an error. Movements for items, locations or bins the website does not sell from are stored and reported (unmatched, ignored), never rejected, so Business Central can send the complete stream for a location without filtering.

Identification and mapping

Key Content Notes
itemNo Business Central Item No., alphanumeric Mandatory.
itemNo2 Business Central No. 2, the website's 4-digit product code Mandatory [to confirm, BC team] that No. 2 is populated for every website-relevant item. If not, Wine World maintains the mapping in the website back office and itemNo2 becomes optional.
variantCode Business Central variant code Only if variants are used [to confirm, BC team: bottle sizes as items or variants].
unitOfMeasure Business Central unit code (BOT, EA, KAN, KEG, PAK observed) Quantities are in this unit. The website sells in the base unit; a movement in another unit is converted by Business Central before transmission [to confirm].
locationCode Business Central location code, 4-digit numeric observed (1401, 1403) Must match an outlet code in the website back office. Outlets are a maintained list; a new location is created before Business Central starts sending for it.
binCode Bin affected AD01 is the saleable bin per the Business Central team's response. Only movements in the saleable bin configured for the location are applied; others are recorded as ignored. A bin transfer out of AD01 is outbound, into AD01 inbound, between two non-saleable bins ignored. [to confirm, WW: AD01 at every location]

Document types and triggers

Adopted from the Business Central team's response of 23 October 2026 as the working list, subject to Wine World's confirmation.

documentType Transaction Direction Trigger (stage)
POS_SALE POS sale Outbound (-) On posting the POS transaction (posted)
POS_RETURN POS sales return Inbound (+) On posting the POS transaction containing return quantities (posted). May share a payload with POS_SALE lines of the same transaction.
CORP_SO Corporate sales order Outbound (-) On receipt of the order in the Shop BC database (requested)
CORP_SO_RETURN Corporate sales return order Inbound (+) On posting the return where the stock becomes saleable (posted)
PURCH_RETURN Purchase return request Outbound (-) On submission for approval (requested)
PURCH_RECEIPT Purchase receipt (GRN) Inbound (+) On posting the receipt (posted)
BIN_TRANSFER Bin transfer Outbound (-) leaving AD01, inbound (+) entering AD01 Leaving AD01: on submission for approval (requested). Entering AD01: on posting the approved transfer (posted).
TRANSFER_ORDER Transfer order between locations Outbound (-) at the sending location, inbound (+) at the receiving location Sending: on initiating the request for website-relevant items from AD01 (requested). Receiving: on posting the transfer receipt into AD01 (posted).
ADJ_NEGATIVE Negative inventory adjustment Outbound (-) On submission for approval (requested)
ADJ_POSITIVE Positive inventory adjustment Inbound (+) On posting (posted)
WEB_ORDER_POST POS transaction created from a website sales order Outbound (-) On posting. Carries websiteOrderRef; see processing rule 5.

Reversals, corrections and completion

An outbound quantity communicated at the request stage is not sent again on posting, is restored on rejection or cancellation, and is adjusted by the difference on amendment or partial processing.

Situation Movement sent stage relatedEventRef
Request submitted negative quantity requested -
Request approved and posted, same quantity no movement - -
Request amended upwards before posting negative difference requested the original event
Request amended downwards, rejected or cancelled positive difference, or the full quantity released the original event
Request completed with a remainder not processed positive remainder released the original event
Posted movement later found wrong signed correction corrected the original event

Processing rules on the website

  1. The batch is validated as a whole for structure and authentication. A structurally invalid batch is rejected (HTTP 400) and nothing in it is stored.
  2. Every structurally valid movement is written to the inventory event store with status stored before the response is returned. A movement whose (sourceSystem, eventRef) already exists is not stored again and is reported as duplicate.
  3. A background process applies stored movements per location in order of occurredAt, then receipt. Applying a movement adds quantity to the location's saleable balance for the item, writes a row to the website's stock ledger with the Business Central references, and marks the event applied. Website availability is recomputed from the new balance.
  4. A movement for an item not in the website product master, for a location not in the outlet list, or for a bin other than the location's saleable bin is stored and marked unmatched or ignored respectively. It is not applied and is listed on the reconciliation report.
  5. Web orders. When the website places an order it reserves the quantity against the outlet's balance. When Business Central posts the POS transaction for that order it sends a WEB_ORDER_POST movement carrying websiteOrderRef. The website applies the negative quantity to the balance and releases the matching web reservation for that order and item, so the stock is reduced once, not twice. A WEB_ORDER_POST movement whose websiteOrderRef is unknown is applied to the balance and reported.
  6. A released movement is applied as a positive quantity. If its relatedEventRef is known and the cumulative releases against that event exceed the quantity originally requested, the movement is still applied and the excess is reported.
  7. Applying a movement never drives the saleable balance below zero. A movement that would do so sets the balance to zero, marks the event applied_clamped and reports it for reconciliation.
  8. Every applied movement is recorded in the website's append-only audit trail with the Business Central references.
  9. Applied events are retained for 90 days [proposed default, configurable] and then purged; the stock ledger rows and the audit trail are retained.

Capacity, throttling and retry

Limit Proposed default Configurable
Requests per minute per client credential 300 Yes
Movements per request 500 Yes
Request size 1 MB Yes
Processing target Movements applied within 60 seconds of receipt under normal load Monitored
Response time Within 5 seconds in normal operation; no response is treated by Business Central as a failure and retried -

The limits are confirmed once Wine World and the Business Central team provide the transaction volumes requested in Section 6.2 of the governing document (POS transactions per location per day and in the peak hour; lines per transaction; other movements per day; locations per roll-out stage; longest outage to plan for; retry interval and batching). Expected transmission behaviour on the Business Central side: transmission at the event with no dependency that delays POS posting; a retry queue; exponential back-off on 5xx and no-response starting at 30 seconds and capped at 15 minutes [proposed]; Retry-After honoured on 429; the original eventRef and batchId preserved on retry; a 400 raised to an operator and not retried; after a store outage the backlog released oldest first in batches of up to 500.

Environments, security and testing

Website sandbox and production, Business Central sandbox and production, with credentials per environment and never shared across. TLS 1.2 or higher; least-privilege service principal; no customer personal data in inventory payloads. All inbound requests are logged with source, size and outcome. The test plan (contract test with the examples in this document; snapshot plus 48 hours of live movements from store 1401 against the website sandbox in parallel with the stock file; burst test; duplicate and reversal cases; web order round trip) and the per-location go-live sequence are in Section 8 of the governing document.

Inventory movements

Event-driven transmission of inventory movements from Shop Business Central to the website, one request per batch, store-then-acknowledge. Section 4 of the governing document.

Receive a batch of inventory movements

Receives one transmission batch of signed inventory movements from a Business Central environment, stores every structurally valid movement durably, and acknowledges with the outcome per movement.

Batching. Business Central batches movements per location per transmission run. One POS transaction is never split across requests. A batch holds 1 to 500 movements [proposed default] and at most 1 MB [proposed default].

Retry. The same batchId and the same eventRef values are repeated on a retry of the same batch. A 200 means the batch is the website's responsibility from this point and must not be retransmitted. Every per-movement status in a 200 response (stored, duplicate, unmatched, ignored) is final; none requires retransmission.

Authorizations:
entraClientCredentials
Request Body schema: application/json
required
batchId
required
string <= 50 characters

Unique per transmission. Repeated on retry of the same batch.

sourceSystem
required
string <= 30 characters

Identifies the sending Business Central environment, for example BC-SHOP-1401 or BC-HO. Part of the duplicate key.

sentAt
required
string <date-time>

Time of transmission, ISO 8601 with offset.

required
Array of objects (InventoryMovement) [ 1 .. 500 ] items

Movements in the order they occurred. Maximum 500 per request [proposed default].

Responses

Response Schema: application/json
batchId
required
string
receivedAt
required
string <date-time>
accepted
required
integer

Movements stored in this request (statuses stored, unmatched and ignored).

duplicates
required
integer

Movements already held from an earlier request.

required
Array of objects (MovementResult)
Response Schema: application/json
error
required
string
Enum: "validation_failed" "unauthorised" "payload_too_large" "rate_limited" "internal_error" "unavailable"

Machine-readable code.

message
required
string

Human-readable detail. For validation_failed, names the first failing field and movement index.

batchId
string

Echoed from the request when it could be read.

Request samples

Content type
application/json
Example
{
  • "batchId": "1401-20261023-000871",
  • "sourceSystem": "BC-SHOP-1401",
  • "sentAt": "2026-10-23T10:14:07+05:30",
  • "movements": [
    • {
      • "eventRef": "POS-1401-55021-1",
      • "occurredAt": "2026-10-23T10:13:52+05:30",
      • "locationCode": "1401",
      • "binCode": "AD01",
      • "itemNo": "AEINGNCEG14H",
      • "itemNo2": "2938",
      • "unitOfMeasure": "BOT",
      • "quantity": -2,
      • "documentType": "POS_SALE",
      • "stage": "posted",
      • "documentNo": "POS-1401-55021",
      • "documentLineNo": 1
      },
    • {
      • "eventRef": "POS-1401-55021-2",
      • "occurredAt": "2026-10-23T10:13:52+05:30",
      • "locationCode": "1401",
      • "binCode": "AD01",
      • "itemNo": "AEINGNCG004M",
      • "itemNo2": "1918",
      • "unitOfMeasure": "BOT",
      • "quantity": 1,
      • "documentType": "POS_RETURN",
      • "stage": "posted",
      • "documentNo": "POS-1401-55021",
      • "documentLineNo": 2,
      • "reasonCode": "RET"
      }
    ]
}

Response samples

Content type
application/json
{
  • "batchId": "1401-20261023-000871",
  • "receivedAt": "2026-10-23T10:14:08+05:30",
  • "accepted": 3,
  • "duplicates": 1,
  • "results": [
    • {
      • "eventRef": "POS-1401-55021-1",
      • "status": "stored"
      },
    • {
      • "eventRef": "POS-1401-55021-2",
      • "status": "stored"
      },
    • {
      • "eventRef": "POS-1401-55021-3",
      • "status": "unmatched",
      • "reason": "item 510000261 not in website product master"
      },
    • {
      • "eventRef": "POS-1401-55019-1",
      • "status": "duplicate"
      }
    ]
}

Snapshots

Initial balance synchronisation before a location goes live on the movement interface, and on demand thereafter for reconciliation. Section 5 of the governing document. The outlet stock file upload in the website back office remains the manual fallback; applying a stock file for a location on the movement interface sets the balance exactly as a snapshot does.

Receive a saleable balance snapshot for one location

Receives the saleable balance of every website-relevant item at one location as at a stated time. Used before a location goes live on the movement interface and on demand thereafter; a daily snapshot is recommended during the roll-out and at least weekly thereafter [to confirm, WW].

Parts. A snapshot may be split across several requests sharing one snapshotId; the last request carries final: true. Authentication, limits and HTTP responses are as for the movement endpoint.

Effect. When the final part is received, the website sets each item's Business Central-derived balance at the location to the snapshot quantity, applies any stored movements with occurredAt later than asOf, and records the snapshot in the stock ledger. Items at the location not present in the snapshot are set to zero and listed on the reconciliation report.

Authorizations:
entraClientCredentials
Request Body schema: application/json
required
snapshotId
required
string <= 50 characters

Shared by every part of the same snapshot.

sourceSystem
required
string <= 30 characters
locationCode
required
string <= 10 characters
asOf
required
string <date-time>

The time the balances were read in Business Central. Stored movements with occurredAt later than this are applied on top of the snapshot.

final
required
boolean

True on the last part. The snapshot is applied when the final part is received.

required
Array of objects (SnapshotBalance) [ 0 .. 500 ] items

Responses

Response Schema: application/json
snapshotId
required
string
receivedAt
required
string <date-time>
final
required
boolean

Echoes the request. When true, the snapshot has been queued for application.

accepted
required
integer

Balances stored from this part.

required
Array of objects

Only balances that did not match a website product or the saleable bin are listed; matched balances are omitted.

Response Schema: application/json
error
required
string
Enum: "validation_failed" "unauthorised" "payload_too_large" "rate_limited" "internal_error" "unavailable"

Machine-readable code.

message
required
string

Human-readable detail. For validation_failed, names the first failing field and movement index.

batchId
string

Echoed from the request when it could be read.

Request samples

Content type
application/json
{
  • "snapshotId": "SNAP-1401-20261101",
  • "sourceSystem": "BC-SHOP-1401",
  • "locationCode": "1401",
  • "asOf": "2026-11-01T06:00:00+05:30",
  • "final": true,
  • "balances": [
    • {
      • "itemNo": "AEINGNCEG14H",
      • "itemNo2": "2938",
      • "unitOfMeasure": "BOT",
      • "binCode": "AD01",
      • "quantity": 9
      },
    • {
      • "itemNo": "AEINGNCG008H",
      • "itemNo2": "2458",
      • "unitOfMeasure": "BOT",
      • "binCode": "AD01",
      • "quantity": 0
      }
    ]
}

Response samples

Content type
application/json
{
  • "snapshotId": "SNAP-1401-20261101",
  • "receivedAt": "2026-11-01T06:00:04+05:30",
  • "final": true,
  • "accepted": 2,
  • "results": [ ]
}