Skip to main content

Example: identifiers in a receipt

This example follows one receipt from your system into the WMS and back, and shows every kind of identifier on the way. The rules themselves are on Building the payload; here they are applied to real requests.

The situation: your system has a new product, code prod-0042, and a receipt rcpt-2026-0105 that expects 24 pieces of it. The warehouse and the unit "pcs" were set up in the WMS, and you know their WMS identifiers.

The structure of a receipt is the schema of the regular API: POST /api/v1/inbound/receipts (ReceiptIncomeDto) for what you send, GET /api/v1/inbound/receipts/{id} (ReceiptFullResponseDto) for what you read.

1. Send the product and the receipt together​

{
"externalSystemCode": "ERP_MAIN",
"items": [
{
"entityType": "PRODUCT",
"importMode": "UPSERT",
"payload": {
"id": "prod-0042",
"name": "Chocolate 100 g",
"isGroup": false,
"type": "PRODUCT",
"uomId": {"wmsId": "01a16373-d330-729f-80db-29830ee809b9"}
}
},
{
"entityType": "RECEIPT",
"importMode": "UPSERT",
"payload": {
"id": "rcpt-2026-0105",
"status": "TO_RECEIVE",
"date": "2026-10-27",
"warehouseId": {"wmsId": "01a16373-d6be-7746-8eab-fc8e447bfea8"},
"senderContainerHandlingMode": "NOT_USED",
"receivingContainerRequirement": "NONE",
"qcRequired": false,
"allowOverReceiving": false,
"lines": [
{"lineNumber": 1, "productId": "prod-0042", "quantity": 24, "packQuantity": 24}
]
}
}
]
}

What each identifier is:

FieldValueForm
product idprod-0042your identifier of the product
product uomId{"wmsId": "01a16373-d330-…"}a WMS identifier: the unit exists only in the WMS
receipt idrcpt-2026-0105your identifier of the document
receipt warehouseId{"wmsId": "01a16373-d6be-…"}a WMS identifier: the warehouse exists only in the WMS
lines[0].productIdprod-0042your identifier of the product sent earlier in the same request

The product goes first: items are applied in order, and the receipt line can refer to the product only after it exists.

2. Read the answer​

{
"results": [
{"itemIndex": 0, "entityType": "PRODUCT", "status": "CREATED", "internalEntityId": "01a17a6f-6056-706b-a37c-0eb5fa84eb29", "errors": []},
{"itemIndex": 1, "entityType": "RECEIPT", "status": "CREATED", "internalEntityId": "01a17a6f-60a6-77be-b765-b7e9341d7efe", "errors": []}
]
}

Both items were created. From now on the WMS knows that prod-0042 and rcpt-2026-0105 are yours: you can refer to them by these codes in any later request, and you do not need to store the internalEntityId values.

Had the product failed, the receipt would fail too, with an error on lines[0].productId — the line refers to a product the WMS does not know.

// Sends a new product and a receipt of that product in one import request.
// The product is identified by your code; the receipt line refers to it by
// the same code. The warehouse and the unit were set up in the WMS, so they
// are referred to by their WMS identifiers.
async function sendProductAndReceipt({productCode, productName, uomWmsId, receiptCode, warehouseWmsId, date, quantity}) {
const {response, failed} = await importItems([
{
entityType: 'PRODUCT',
importMode: 'UPSERT',
payload: {
id: productCode, // your identifier
name: productName,
isGroup: false,
type: 'PRODUCT',
uomId: {wmsId: uomWmsId}, // a WMS identifier
},
},
{
entityType: 'RECEIPT',
importMode: 'UPSERT',
payload: {
id: receiptCode, // your identifier of the document
status: 'TO_RECEIVE',
date,
warehouseId: {wmsId: warehouseWmsId}, // a WMS identifier
senderContainerHandlingMode: 'NOT_USED',
receivingContainerRequirement: 'NONE',
qcRequired: false,
allowOverReceiving: false,
lines: [
{lineNumber: 1, productId: productCode, quantity, packQuantity: quantity}, // your identifier
],
},
},
]);
if (failed.length > 0) throw new Error('The receipt was not imported');
const [product, receipt] = response.results;
return {productId: product.internalEntityId, receiptId: receipt.internalEntityId};
}

3. Receive the receipt back​

When the receipt changes in the WMS — the goods are received, the receipt is confirmed — the change feed delivers its current state. Only changes made in the WMS come back: the receipt your system just sent does not return as an echo of its own request. The part of the payload with identifiers:

{
"id": {"int": "01a17a6f-60a6-77be-b765-b7e9341d7efe", "ext": "rcpt-2026-0105"},
"externalId": "rcpt-2026-0105",
"status": "TO_RECEIVE",
"warehouseId": {"int": "01a16373-d6be-7746-8eab-fc8e447bfea8", "ext": null},
"receivingZoneId": {"int": "01a16373-d73d-7668-89c6-b4e961c83766", "ext": null},
"createdById": {"int": "01a17a4a-af8d-75b2-bafd-7cf085aa6dac", "ext": null},
"executions": [
{
"lineNumber": 1,
"productId": {"int": "01a17a6f-6056-706b-a37c-0eb5fa84eb29", "ext": "prod-0042"},
"quantityPlan": "24.0000",
"quantityExecuted": "0.0000",
"locationId": {"int": "01a16373-d73d-7668-89c6-b4e961c83766", "ext": null}
}
]
}
  • id.ext and executions[].productId.ext hold your codes: find the document and the product in your system by them.
  • warehouseId.ext is null: the warehouse was never sent by your system. Match it by the int you used in {"wmsId": …}.
  • receivingZoneId was not in your request: the WMS filled it from the warehouse settings. Its ext is null too.
  • createdById is a WMS user. Users never have an ext.
  • Quantities are decimal numbers in strings. Convert them to a decimal type.
  • The receipt lines come back in executions, with the planned and the received quantity of each line.
// Turns a receipt payload from the change feed into what your system needs.
// Every identifier is a pair: `int` is the WMS identifier, `ext` is yours
// (null when the record did not come from your system).
function readReceipt(payload) {
return {
wmsId: payload.id.int,
externalId: payload.id.ext, // the `id` you sent, in lower case
status: payload.status,
warehouse: payload.warehouseId,
createdBy: payload.createdById, // a WMS user: `ext` is always null
lines: payload.executions.map((line) => ({
lineNumber: line.lineNumber,
product: line.productId,
planned: Number(line.quantityPlan),
received: Number(line.quantityExecuted),
})),
};
}

// Finds your record by your identifier, or by a WMS identifier you stored before.
function findLocalRecord(ref, localByCode, localByWmsId) {
return (ref.ext && localByCode.get(ref.ext)) ?? localByWmsId.get(ref.int);
}

// Usage with the change feed:
// await pollChangeFeed(async (event, payload) => {
// if (event.entityType !== 'RECEIPT') return; // other types are handled elsewhere
// const receipt = readReceipt(payload);
// for (const line of receipt.lines) {
// const product = findLocalRecord(line.product, productsByCode, productsByWmsId);
// // ... update the received quantity of `product` in your document `receipt.externalId`
// }
// });