Order feed
The order feed allows the merchant to push order data into the OpenApp recommendation engine. For every order, the feed contains the purchased basket - product id, ean, quantities and prices - and the identifier of the user who placed it.
Orders placed through the OpenApp checkout are ingested into the recommendation engine automatically. Sending them through this feed as well is redundant - re-sending an orderId replaces the stored order, so no harm is done, but there is nothing to gain. Use this feed for orders from your other sales channels (own webshop checkout, mobile app, physical stores).
After the initial catalogue ingestion, OpenApp needs time to process the data before order ingestion and recommendations retrieval become available. Until processing completes, the endpoint responds 409 RecommendationsNotReadyException. Wait for confirmation from OpenApp before starting the backfill.
Two usage patterns are supported by the same endpoint:
- Initial backfill: after activation, push your order history (we recommend at least the last 12 months) in batches to give the engine a warm start. Do not include cancelled orders in the initial backfill; only send cancellations for orders that were previously ingested.
- Ongoing feed: push new orders as they are placed, individually or in periodic batches (for example hourly).
Request
Orders are pushed by a POST to the following endpoint:
POST {{OpenAppUrl}}/merchant/v1/recommendations/orders
A single request can contain at most 100 orders.
- Request
- Schema
{
"orders": [
{
"orderId": "WS1213ASDZXC231A",
"loggedUser": "user-id-from-webshop",
"createdAt": "2026-06-09T17:23:00.000Z",
"channel": "WEB",
"currency": "PLN",
"products": [
{
"id": "id123-red",
"ean": "5901234123457",
"quantity": 2,
"unitPrice": 6000,
"linePrice": 12000
},
{
"id": "id124",
"ean": "5901234123464",
"quantity": 1,
"unitPrice": 6000,
"linePrice": 6000
}
]
},
{
"orderId": "WS1213ASDZXC231B",
"loggedUser": "user-id-from-webshop",
"status": "CANCELLED",
"createdAt": "2026-06-09T18:05:00.000Z",
"channel": "IN_STORE",
"currency": "PLN",
"products": [
{
"id": "id124",
"ean": "5901234123464",
"quantity": 3,
"unitPrice": 5500,
"linePrice": 16500
}
]
}
]
}
ordersarray of RecommendationOrderRequiredThe orders to ingest.
minItems: 1 · maxItems: 100
Show child parametersHide child parameters7
orderIdstringRequiredThe unique ID of the order in the merchant system.
maxLength: 36
loggedUserstringRequiredThe merchant's own stable identifier for the user.
maxLength: 255
createdAtstringRequiredThe moment the order was placed in the merchant system.
format: date-time
statusenumOptionalThe status of the order. Re-send an order with CANCELLED to remove it from the recommendation engine when the user cancels it. Defaults to CREATED.
Possible values: CREATEDCANCELLED
channelenumOptionalThe sales channel the order was placed through.
Possible values: WEBMOBILE_APPIN_STOREOTHER
currencystringRequiredThe currency of all prices in the order.
productsarray of RecommendationOrderProductRequiredThe products purchased in the order.
minItems: 1
Show child parametersHide child parameters5
idstringRequiredThe catalogue variant ID of the purchased product.
maxLength: 36
eanstringOptionalThe ean (or other barcode) of the product.
maxLength: 36
quantityintegerRequiredThe number of items in the purchase.
minimum: 1
unitPriceintegerRequiredThe price paid for a single product. Price is expressed as the number (integer) of 1/100s of the price.
minimum: 0
linePriceintegerOptionalThe price paid for the products. Price is expressed as the number (integer) of 1/100s of the price.
minimum: 0
Raw JSON Schema
{
"description": "Batch of orders fed by the merchant into the OpenApp recommendation engine - historical backfill, ongoing orders, and status updates.",
"additionalProperties": false,
"type": "object",
"properties": {
"orders": {
"description": "The orders to ingest.",
"maxItems": 100,
"minItems": 1,
"type": "array",
"items": {
"$ref": "#/definitions/RecommendationOrder"
},
"title": "orders"
}
},
"required": [
"orders"
],
"definitions": {
"RecommendationOrder": {
"title": "RecommendationOrder",
"type": "object",
"properties": {
"orderId": {
"description": "The unique ID of the order in the merchant system.",
"maxLength": 36,
"type": "string",
"title": "orderId"
},
"loggedUser": {
"description": "The merchant's own stable identifier for the user.",
"maxLength": 255,
"type": "string",
"title": "loggedUser"
},
"createdAt": {
"description": "The moment the order was placed in the merchant system.",
"format": "date-time",
"type": "string",
"title": "createdAt"
},
"status": {
"description": "The status of the order. Re-send an order with CANCELLED to remove it from the recommendation engine when the user cancels it. Defaults to CREATED.",
"enum": [
"CREATED",
"CANCELLED"
],
"type": "string",
"title": "status"
},
"channel": {
"description": "The sales channel the order was placed through.",
"enum": [
"WEB",
"MOBILE_APP",
"IN_STORE",
"OTHER"
],
"type": "string",
"title": "channel"
},
"currency": {
"description": "The currency of all prices in the order.",
"type": "string",
"title": "currency"
},
"products": {
"description": "The products purchased in the order.",
"minItems": 1,
"type": "array",
"items": {
"$ref": "#/definitions/RecommendationOrderProduct"
},
"title": "products"
}
},
"required": [
"currency",
"loggedUser",
"orderId",
"createdAt",
"products"
]
},
"RecommendationOrderProduct": {
"title": "RecommendationOrderProduct",
"type": "object",
"properties": {
"id": {
"description": "The catalogue variant ID of the purchased product.",
"maxLength": 36,
"type": "string",
"title": "id"
},
"ean": {
"description": "The ean (or other barcode) of the product.",
"maxLength": 36,
"type": "string",
"title": "ean"
},
"quantity": {
"description": "The number of items in the purchase.",
"minimum": 1,
"type": "integer",
"title": "quantity"
},
"unitPrice": {
"description": "The price paid for a single product. Price is expressed as the number (integer) of 1/100s of the price.",
"minimum": 0,
"type": "integer",
"title": "unitPrice"
},
"linePrice": {
"description": "The price paid for the products. Price is expressed as the number (integer) of 1/100s of the price.",
"minimum": 0,
"type": "integer",
"title": "linePrice"
}
},
"required": [
"id",
"quantity",
"unitPrice"
]
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}
The loggedUser value is the merchant's own stable user identifier - OpenApp does not attempt to associate it with any OpenApp account. Every order must identify the user who placed it.
The product id must match the catalogue variant id. Products not yet known from the catalogue are ignored and reported back in ignoredProducts - the order itself is still ingested. Because re-sending an orderId replaces the stored order, the merchant can re-send a previously rejected or partially ignored order after the next catalogue synchronization to capture the missing products.
Order status and cancellations
The optional status field defaults to CREATED. When a user cancels an order that has already been sent to the feed, re-send it with status: CANCELLED - OpenApp will remove it from the recommendation engine. Because ingestion is an upsert on orderId, the cancellation is applied by replacing the order with its cancelled counterpart.
Response
Orders are ingested independently: a problem with one order does not affect the rest of the batch. OpenApp responds with 200 OK containing the number of accepted orders, a rejected list for orders that failed validation, and an ignoredProducts list for products that were unknown to the catalogue.
- Response
- Schema
{
"accepted": 99,
"rejected": [
{
"orderId": "WS1213ASDZXC231F",
"error": "VALIDATION_FAILED",
"message": "createdAt is missing"
}
],
"ignoredProducts": [
{
"orderId": "WS1213ASDZXC231A",
"productIds": [
"id999"
]
}
]
}
acceptedintegerRequiredThe number of orders from the request that were ingested.
minimum: 0
rejectedarray of RejectedOrderRequiredThe orders from the request that were not ingested, with the rejection reason. Empty when all orders were accepted.
Show child parametersHide child parameters3
orderIdstringRequiredThe ID of the rejected order, as sent in the request.
maxLength: 36
errorenumRequiredThe rejection reason. VALIDATION_FAILED - the order data is semantically invalid.
Possible values: VALIDATION_FAILED
messagestringOptionalA human-readable description of the rejection reason.
maxLength: 255
ignoredProductsarray of IgnoredProductsRequiredProducts that were ignored during ingestion because they are not yet known from the catalogue, grouped per order. The orders themselves were ingested. Re-send the order after the next catalogue synchronization to capture these products.
Show child parametersHide child parameters2
orderIdstringRequiredThe ID of the order whose products were partially ignored.
maxLength: 36
productIdsarray of stringRequiredThe IDs of the products that were ignored because they are not known from the catalogue.
Raw JSON Schema
{
"description": "The result of ingesting a batch of orders into the OpenApp recommendation engine",
"additionalProperties": false,
"type": "object",
"properties": {
"accepted": {
"description": "The number of orders from the request that were ingested.",
"minimum": 0,
"type": "integer",
"title": "accepted"
},
"rejected": {
"description": "The orders from the request that were not ingested, with the rejection reason. Empty when all orders were accepted.",
"type": "array",
"items": {
"$ref": "#/definitions/RejectedOrder"
},
"title": "rejected"
},
"ignoredProducts": {
"description": "Products that were ignored during ingestion because they are not yet known from the catalogue, grouped per order. The orders themselves were ingested. Re-send the order after the next catalogue synchronization to capture these products.",
"type": "array",
"items": {
"$ref": "#/definitions/IgnoredProducts"
},
"title": "ignoredProducts"
}
},
"required": [
"accepted",
"rejected",
"ignoredProducts"
],
"definitions": {
"RejectedOrder": {
"title": "RejectedOrder",
"type": "object",
"properties": {
"orderId": {
"description": "The ID of the rejected order, as sent in the request.",
"maxLength": 36,
"type": "string",
"title": "orderId"
},
"error": {
"description": "The rejection reason. VALIDATION_FAILED - the order data is semantically invalid.",
"enum": [
"VALIDATION_FAILED"
],
"type": "string",
"title": "error"
},
"message": {
"description": "A human-readable description of the rejection reason.",
"maxLength": 255,
"type": "string",
"title": "message"
}
},
"required": [
"orderId",
"error"
]
},
"IgnoredProducts": {
"title": "IgnoredProducts",
"type": "object",
"properties": {
"orderId": {
"description": "The ID of the order whose products were partially ignored.",
"maxLength": 36,
"type": "string",
"title": "orderId"
},
"productIds": {
"description": "The IDs of the products that were ignored because they are not known from the catalogue.",
"type": "array",
"items": {
"maxLength": 36,
"type": "string"
},
"title": "productIds"
}
},
"required": [
"orderId",
"productIds"
]
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}
The whole request fails only when the request itself is malformed or too large - see the errors below.
Errors
| Error name | Code |
|---|---|
OrderValidationException | 400 |
TooManyOrdersException | 413 |
RecommendationsNotReadyException | 409 |