User recommendations
The user recommendations call returns three lists of products tailored to a specific user:
topPicks- products the user should buy right now.replenishment- products the user regularly buys but does not need right now.discovery- products the user might be interested in.
Every item, in any of the three lists, may carry alternatives - substitute products to show instead if the item itself cannot be displayed (e.g. out of stock by the time of rendering).
Request
Recommendations are requested by a POST to the following endpoint:
POST {{OpenAppUrl}}/merchant/v1/recommendations/user
- Request
- Schema
{
"loggedUser": "user-id-from-webshop",
"limits": {
"topPicks": {
"items": 3,
"alternatives": 2
},
"replenishment": {
"items": 5,
"alternatives": 1
},
"discovery": {
"items": 5,
"alternatives": 1
}
}
}
loggedUserstringRequiredThe merchant's own stable identifier for the user.
maxLength: 255
limitsobjectOptionalMaximum number of items to return per list. All fields are optional; omit to use the defaults.
Show child parametersHide child parameters3
topPicksobjectOptionalLimits for the topPicks list. All fields are optional; omit to use the defaults.
Show child parametersHide child parameters2
itemsintegerOptionalMaximum number of top-pick items to return. Defaults to 20.
minimum: 1 · maximum: 200
alternativesintegerOptionalMaximum number of alternative products to return per top-pick item. Defaults to 3.
minimum: 0 · maximum: 10
replenishmentobjectOptionalLimits for the replenishment list. All fields are optional; omit to use the defaults.
Show child parametersHide child parameters2
itemsintegerOptionalMaximum number of replenishment items to return. Defaults to 20.
minimum: 1 · maximum: 200
alternativesintegerOptionalMaximum number of alternative products to return per replenishment item. Defaults to 3.
minimum: 0 · maximum: 10
discoveryobjectOptionalLimits for the discovery list. All fields are optional; omit to use the defaults.
Show child parametersHide child parameters2
itemsintegerOptionalMaximum number of discovery items to return. Defaults to 20.
minimum: 1 · maximum: 200
alternativesintegerOptionalMaximum number of alternative products to return per discovery item. Defaults to 3.
minimum: 0 · maximum: 10
Raw JSON Schema
{
"description": "Request for product recommendations for a user",
"additionalProperties": false,
"type": "object",
"properties": {
"loggedUser": {
"description": "The merchant's own stable identifier for the user.",
"maxLength": 255,
"type": "string",
"title": "loggedUser"
},
"limits": {
"description": "Maximum number of items to return per list. All fields are optional; omit to use the defaults.",
"additionalProperties": false,
"type": "object",
"properties": {
"topPicks": {
"description": "Limits for the topPicks list. All fields are optional; omit to use the defaults.",
"additionalProperties": false,
"type": "object",
"properties": {
"items": {
"description": "Maximum number of top-pick items to return. Defaults to 20.",
"minimum": 1,
"maximum": 200,
"type": "integer",
"title": "items"
},
"alternatives": {
"description": "Maximum number of alternative products to return per top-pick item. Defaults to 3.",
"minimum": 0,
"maximum": 10,
"type": "integer",
"title": "alternatives"
}
},
"title": "topPicks"
},
"replenishment": {
"description": "Limits for the replenishment list. All fields are optional; omit to use the defaults.",
"additionalProperties": false,
"type": "object",
"properties": {
"items": {
"description": "Maximum number of replenishment items to return. Defaults to 20.",
"minimum": 1,
"maximum": 200,
"type": "integer",
"title": "items"
},
"alternatives": {
"description": "Maximum number of alternative products to return per replenishment item. Defaults to 3.",
"minimum": 0,
"maximum": 10,
"type": "integer",
"title": "alternatives"
}
},
"title": "replenishment"
},
"discovery": {
"description": "Limits for the discovery list. All fields are optional; omit to use the defaults.",
"additionalProperties": false,
"type": "object",
"properties": {
"items": {
"description": "Maximum number of discovery items to return. Defaults to 20.",
"minimum": 1,
"maximum": 200,
"type": "integer",
"title": "items"
},
"alternatives": {
"description": "Maximum number of alternative products to return per discovery item. Defaults to 3.",
"minimum": 0,
"maximum": 10,
"type": "integer",
"title": "alternatives"
}
},
"title": "discovery"
}
},
"title": "limits"
}
},
"required": [
"loggedUser"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}
Each list has a configurable items limit (default 20, max 200) and a configurable alternatives limit, capping the number of alternative products returned per item in that list (default 3, max 10). Omit limits or any of its fields to use the defaults.
Response
- Response
- Schema
{
"topPicks": [
{
"id": "id124",
"ean": "5901234123464",
"quantity": 1,
"alternatives": [
{
"id": "id123-red",
"ean": "5901234123457",
"quantity": 1
}
]
}
],
"replenishment": [
{
"id": "id123-red",
"ean": "5901234123457",
"quantity": 2,
"expectedAt": "2026-06-20T00:00:00.000Z",
"alternatives": [
{
"id": "id124",
"ean": "5901234123464",
"quantity": 2
}
]
}
],
"discovery": [
{
"id": "id123-blue",
"ean": "5901234123471",
"quantity": 1,
"score": 0.44,
"alternatives": [
{
"id": "id123-red",
"ean": "5901234123457",
"quantity": 1
}
]
}
],
"expiresAt": "2026-06-10T09:42:00.000Z"
}
topPicksarray of RecommendedProductRequiredProducts the user should buy right now, ordered in a stable sort order. Applying a presentation order pleasant for the user (e.g. grouping by product category) is the merchant's responsibility.
Show child parametersHide child parameters4
idstringRequiredThe catalogue variant ID of the recommended product.
maxLength: 36
eanstringOptionalThe ean (or other barcode) of the recommended product, as known from the catalogue.
maxLength: 36
quantityintegerRequiredThe proposed number of items to add to the basket.
minimum: 1
alternativesarray of AlternativeProductOptionalSubstitute products to offer instead of this item if it cannot be shown, e.g. because it is out of stock by the time of display. Ordered by relevance; the merchant may show any number of them, including none. Bounded by limits.topPicks.alternatives.
Show child parametersHide child parameters3
idstringRequiredThe catalogue variant ID of the alternative product.
maxLength: 36
eanstringOptionalThe ean (or other barcode) of the alternative product, as known from the catalogue.
maxLength: 36
quantityintegerRequiredThe proposed number of items to add to the basket.
minimum: 1
replenishmentarray of ReplenishmentProductRequiredProducts the user regularly buys but does not need right now - returned in a stable sort order. Each item includes an expectedAt date indicating when the user is expected to want to buy it. A product that appears in topPicks will not appear here. Applying a presentation order pleasant for the user (e.g. grouping by product category) is the merchant's responsibility.
Show child parametersHide child parameters5
idstringRequiredThe catalogue variant ID of the recommended product.
maxLength: 36
eanstringOptionalThe ean (or other barcode) of the recommended product, as known from the catalogue.
maxLength: 36
quantityintegerRequiredThe proposed number of items to add to the basket.
minimum: 1
expectedAtstringRequiredThe moment when the user is expected to want to buy this product.
format: date-time
alternativesarray of AlternativeProductOptionalSubstitute products to offer instead of this item if it cannot be shown, e.g. because it is out of stock by the time of display. Ordered by relevance; the merchant may show any number of them, including none. Bounded by limits.replenishment.alternatives.
Show child parametersHide child parameters3
idstringRequiredThe catalogue variant ID of the alternative product.
maxLength: 36
eanstringOptionalThe ean (or other barcode) of the alternative product, as known from the catalogue.
maxLength: 36
quantityintegerRequiredThe proposed number of items to add to the basket.
minimum: 1
discoveryarray of DiscoveryProductRequiredProducts the user might be interested in, returned in a stable sort order. Each item carries a relevance score. Applying a presentation order pleasant for the user (e.g. grouping by product category) is the merchant's responsibility.
Show child parametersHide child parameters5
idstringRequiredThe catalogue variant ID of the recommended product.
maxLength: 36
eanstringOptionalThe ean (or other barcode) of the recommended product, as known from the catalogue.
maxLength: 36
quantityintegerRequiredThe proposed number of items to add to the basket.
minimum: 1
scorenumberRequiredThe relevance of the recommendation, between 0 and 1. Higher is more relevant.
minimum: 0 · maximum: 1
alternativesarray of AlternativeProductOptionalSubstitute products to offer instead of this item if it cannot be shown, e.g. because it is out of stock by the time of display. Ordered by relevance; the merchant may show any number of them, including none. Bounded by limits.discovery.alternatives.
Show child parametersHide child parameters3
idstringRequiredThe catalogue variant ID of the alternative product.
maxLength: 36
eanstringOptionalThe ean (or other barcode) of the alternative product, as known from the catalogue.
maxLength: 36
quantityintegerRequiredThe proposed number of items to add to the basket.
minimum: 1
expiresAtstringOptionalThe moment until which the recommendations can be cached and reused for the same user. When absent, the response must not be cached.
format: date-time
Raw JSON Schema
{
"description": "Product recommendations returned for a user",
"additionalProperties": false,
"type": "object",
"properties": {
"topPicks": {
"description": "Products the user should buy right now, ordered in a stable sort order. Applying a presentation order pleasant for the user (e.g. grouping by product category) is the merchant's responsibility.",
"type": "array",
"items": {
"$ref": "#/definitions/RecommendedProduct"
},
"title": "topPicks"
},
"replenishment": {
"description": "Products the user regularly buys but does not need right now - returned in a stable sort order. Each item includes an expectedAt date indicating when the user is expected to want to buy it. A product that appears in topPicks will not appear here. Applying a presentation order pleasant for the user (e.g. grouping by product category) is the merchant's responsibility.",
"type": "array",
"items": {
"$ref": "#/definitions/ReplenishmentProduct"
},
"title": "replenishment"
},
"discovery": {
"description": "Products the user might be interested in, returned in a stable sort order. Each item carries a relevance score. Applying a presentation order pleasant for the user (e.g. grouping by product category) is the merchant's responsibility.",
"type": "array",
"items": {
"$ref": "#/definitions/DiscoveryProduct"
},
"title": "discovery"
},
"expiresAt": {
"description": "The moment until which the recommendations can be cached and reused for the same user. When absent, the response must not be cached.",
"format": "date-time",
"type": "string",
"title": "expiresAt"
}
},
"required": [
"topPicks",
"replenishment",
"discovery"
],
"definitions": {
"RecommendedProduct": {
"title": "RecommendedProduct",
"type": "object",
"properties": {
"id": {
"description": "The catalogue variant ID of the recommended product.",
"maxLength": 36,
"type": "string",
"title": "id"
},
"ean": {
"description": "The ean (or other barcode) of the recommended product, as known from the catalogue.",
"maxLength": 36,
"type": "string",
"title": "ean"
},
"quantity": {
"description": "The proposed number of items to add to the basket.",
"minimum": 1,
"type": "integer",
"title": "quantity"
},
"alternatives": {
"description": "Substitute products to offer instead of this item if it cannot be shown, e.g. because it is out of stock by the time of display. Ordered by relevance; the merchant may show any number of them, including none. Bounded by limits.topPicks.alternatives.",
"type": "array",
"items": {
"$ref": "#/definitions/AlternativeProduct"
},
"title": "alternatives"
}
},
"required": [
"id",
"quantity"
]
},
"AlternativeProduct": {
"title": "AlternativeProduct",
"type": "object",
"properties": {
"id": {
"description": "The catalogue variant ID of the alternative product.",
"maxLength": 36,
"type": "string",
"title": "id"
},
"ean": {
"description": "The ean (or other barcode) of the alternative product, as known from the catalogue.",
"maxLength": 36,
"type": "string",
"title": "ean"
},
"quantity": {
"description": "The proposed number of items to add to the basket.",
"minimum": 1,
"type": "integer",
"title": "quantity"
}
},
"required": [
"id",
"quantity"
]
},
"ReplenishmentProduct": {
"title": "ReplenishmentProduct",
"type": "object",
"properties": {
"id": {
"description": "The catalogue variant ID of the recommended product.",
"maxLength": 36,
"type": "string",
"title": "id"
},
"ean": {
"description": "The ean (or other barcode) of the recommended product, as known from the catalogue.",
"maxLength": 36,
"type": "string",
"title": "ean"
},
"quantity": {
"description": "The proposed number of items to add to the basket.",
"minimum": 1,
"type": "integer",
"title": "quantity"
},
"expectedAt": {
"description": "The moment when the user is expected to want to buy this product.",
"format": "date-time",
"type": "string",
"title": "expectedAt"
},
"alternatives": {
"description": "Substitute products to offer instead of this item if it cannot be shown, e.g. because it is out of stock by the time of display. Ordered by relevance; the merchant may show any number of them, including none. Bounded by limits.replenishment.alternatives.",
"type": "array",
"items": {
"$ref": "#/definitions/AlternativeProduct"
},
"title": "alternatives"
}
},
"required": [
"id",
"quantity",
"expectedAt"
]
},
"DiscoveryProduct": {
"title": "DiscoveryProduct",
"type": "object",
"properties": {
"id": {
"description": "The catalogue variant ID of the recommended product.",
"maxLength": 36,
"type": "string",
"title": "id"
},
"ean": {
"description": "The ean (or other barcode) of the recommended product, as known from the catalogue.",
"maxLength": 36,
"type": "string",
"title": "ean"
},
"quantity": {
"description": "The proposed number of items to add to the basket.",
"minimum": 1,
"type": "integer",
"title": "quantity"
},
"score": {
"description": "The relevance of the recommendation, between 0 and 1. Higher is more relevant.",
"minimum": 0,
"maximum": 1,
"type": "number",
"title": "score"
},
"alternatives": {
"description": "Substitute products to offer instead of this item if it cannot be shown, e.g. because it is out of stock by the time of display. Ordered by relevance; the merchant may show any number of them, including none. Bounded by limits.discovery.alternatives.",
"type": "array",
"items": {
"$ref": "#/definitions/AlternativeProduct"
},
"title": "alternatives"
}
},
"required": [
"id",
"quantity",
"score"
]
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}
Only products known from the catalogue and currently available are returned. Any list can be shorter than its limit - or empty - when OpenApp has no sufficiently relevant recommendations. For a loggedUser OpenApp has not yet seen in the order feed, all three lists are empty. The merchant should design placements to handle empty lists gracefully.
Items within each list are returned in a stable sort order. Applying a presentation order that is pleasant for the user - for example grouping by product category - is the merchant's responsibility.
Recommendations for a user are recalculated once a day. A product the user has just purchased may still appear in the lists until the next recalculation. The merchant should hide recently purchased products when rendering the placement.
When expiresAt is present, the response can be cached and reused for the same user until that moment - it marks when the next recalculation will be available. When expiresAt is absent, the response must not be cached.
The call may take a few seconds and must not block the user. Fetch recommendations asynchronously - for example ahead of time or in a background request - and render the placement when the response arrives.
Errors
| Error name | Code |
|---|---|
RecommendationValidationException | 400 |
RecommendationsNotReadyException | 409 |