Download OpenAPI specification:
Inventory Movement API and Snapshot API received by the WineWorld.lk website from Dynamics 365 Business Central.
| 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. |
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.
sourceSystem, eventRef). A retransmitted movement is acknowledged as duplicate and is not applied a second time.WEB_ORDER_POST movement carrying websiteOrderRef releases the website's own reservation for that order as it is applied.unmatched, ignored), never rejected, so Business Central can send the complete stream for a location without filtering.| 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] |
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. |
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 |
stored before the response is returned. A movement whose (sourceSystem, eventRef) already exists is not stored again and is reported as duplicate.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.unmatched or ignored respectively. It is not applied and is listed on the reconciliation report.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.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.applied_clamped and reports it for reconciliation.| 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.
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.
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.
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.
| 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 |
| 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]. |
| batchId required | string |
| receivedAt required | string <date-time> |
| accepted required | integer Movements stored in this request (statuses |
| duplicates required | integer Movements already held from an earlier request. |
required | Array of objects (MovementResult) |
| 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 |
| batchId | string Echoed from the request when it could be read. |
{- "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"
}
]
}{- "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"
}
]
}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.
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.
| 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 |
| 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 |
| 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. |
| 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 |
| batchId | string Echoed from the request when it could be read. |
{- "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
}
]
}{- "snapshotId": "SNAP-1401-20261101",
- "receivedAt": "2026-11-01T06:00:04+05:30",
- "final": true,
- "accepted": 2,
- "results": [ ]
}