OpenAPI Reference
Complete OpenAPI specification available for download:
Environments
| Environment | URL |
|---|---|
| Production | https://prod.store-management.glovo.alb.app.onlineservice.io |
Integration, including testing against test stores, runs against this endpoint. Test stores are allocated in the same environment and are distinguished by configuration, not by address.
Menu Validate V3
POST /api/v3/menu/validate
The endpoint allows users to upload a menu and validate it according to the JSON schema. If no errors or warnings are detected, the endpoint will return an all-okay message. If errors or warnings are detected, the endpoint will return a list of errors and warnings, along with detailed information about each error (line number, column number, and error message).
RECOMMENDATION
Validate the payload before sending the menu for execution. This will ensure that the menu is in the correct format and will save time by identifying errors early.
Request Body: application/json — menu payload as JSON string
curl -X POST \
'https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/menu/validate' \
-H 'Authorization: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"store_environment": "prod",
"store_id": "partner__001",
"partner_name": "partner",
"super_categories": [...]
}'import requests
url = "https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/menu/validate"
headers = {
"Authorization": "YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"store_environment": "prod",
"store_id": "partner__001",
"partner_name": "partner",
"super_categories": [...]
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())const response = await fetch(
'https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/menu/validate',
{
method: 'POST',
headers: {
'Authorization': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
store_environment: 'prod',
store_id: 'partner__001',
partner_name: 'partner',
super_categories: [...]
})
}
);
const data = await response.json();HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/menu/validate"))
.header("Authorization", "YOUR_API_KEY")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/menu/validate');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: YOUR_API_KEY',
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonPayload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);req, _ := http.NewRequest("POST",
"https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/menu/validate",
bytes.NewBuffer(jsonPayload))
req.Header.Set("Authorization", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)Responses:
| Status | Description |
|---|---|
200 | Menu Validation Result |
400 | The menu is not valid, or the request could not be read — the reason is in the body |
500 | Internal error |
Response Schema MenuValidationResponse:
{
"valid": true,
"errors": ["string"],
"warnings": ["string"]
}| Field | Type | Description |
|---|---|---|
valid | boolean | Specifies if the menu is valid or not |
errors | array[string] | Detailed information of the errors generated by JSON schema |
warnings | array[string] | Detailed information of the warnings generated by JSON schema |
Upload Menu V3
POST /api/v3/menu/upload
This API endpoint allows users to upload or update the entire menu of a store in Glovo. The process is asynchronous — the endpoint returns a transaction_id that can be used to track the progress using the Check Status endpoint.
DAILY LIMIT
There is a maximum of 5 menu updates allowed per day per store address. If this limit is reached, the endpoint will return status code 429 (Too Many Requests). For small updates to products and attributes, it is recommended to use individual or bulk endpoints.
ATOMIC OPERATION
In the event that the Glovo system encounters an error while updating the menu, no changes will be made to avoid inconsistencies.
Request Body: application/json
{
"store_id": "partner__001",
"store_environment": "prod",
"partner_name": "partner",
"super_categories": [
{
"name": "default",
"position": 0,
"image_url": null,
"display_super_category": false,
"categories": [...]
}
]
}curl -X POST \
'https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/menu/upload' \
-H 'Authorization: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d @menu.jsonimport requests
url = "https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/menu/upload"
headers = {"Authorization": "YOUR_API_KEY", "Content-Type": "application/json"}
response = requests.post(url, json=menu_payload, headers=headers)
print(response.json())Responses:
| Status | Description |
|---|---|
200 | Upload accepted — contains transaction_id |
400 | Invalid request, unknown store, store not activated in Glovo, or menu refused by validation |
429 | Daily limit exceeded — detail carries Glovo's reason |
500 | Internal error — detail carries a reference to quote to integration support |
502 | Glovo could not process the upload or could not be reached; retry later |
Response Schema MenuUploadResponse:
{
"status": "string",
"transaction_id": "a946a2c7-f4e7-46ac-ae63-8a5497cb0ad9",
"message": "string",
"detail": "string"
}transaction_id is returned only with 200. On any other status, message states what failed and detail states what to change — the field path, the value or the store concerned:
{
"status": "ERROR",
"transaction_id": null,
"message": "The menu upload request is invalid",
"detail": "Field 'super_categories[0].categories[1].sections[0].products[0].price' is not a number: '18,00'. Use a dot as the decimal separator, for example \"25.00\".",
"validation": null
}Schema MenuUpdateRequest
| Field | Type | Description |
|---|---|---|
store_id | string | The unique identifier of the store |
store_environment | string | The environment of the store: prod or staging |
partner_name | string | The name of the partner / POS solution |
super_category | SuperCategory | A single super category (backward compatibility V2) |
super_categories | array[SuperCategory] | The list of super categories (V3 — recommended) |
Schema SuperCategory
A "super-category" is the highest level of categorization in the Glovo menu.
| Field | Type | Description |
|---|---|---|
name | string | The name of the super category |
position | integer | The position in the menu |
image_url | string | Image URL (HTTPS required) |
display_super_category | boolean | Whether the super category should be displayed |
categories | array[Category] | The list of categories |
Schema Category
A category is a secondary level of organization in the Glovo menu. It is mandatory to have at least one category. A category is composed of sections and must have at least one section. Examples: beverages, burgers, salads, desserts, pasta.
| Field | Type | Description |
|---|---|---|
name | string | The name of the category |
position | integer | The position of the category in the menu |
image_url | string | The URL of the category image (HTTPS) |
sections | array[Section] | The list of sections within the category |
Schema Section
| Field | Type | Description |
|---|---|---|
name | string | The name of the section |
position | integer | The position of the section |
products | array[Product] | List of products belonging to this section |
Schema Product
A product is a fundamental element of the Glovo menu, typically representing a physical item available in a store. However, the store has the freedom to decide what it wants to offer as products. Each product is associated with a section.
| Field | Type | Description |
|---|---|---|
id | string | The ID of the product (must be unique) |
name | string | The name of the product |
price | string | The price of the product |
imageUrl | string | The URL of the main image (HTTPS required) |
extraImageUrls | array[string] | Additional image URLs (HTTPS, max 9 images) |
description | string | The description of the product |
available | boolean | Whether the product is available (default: true) |
attribute_groups | array[AttributeGroup] | A list of attribute groups |
Schema AttributeGroup
Attribute groups allow grouping similar customizations into generic sets, each of which can have a minimum and maximum number of options for the customer. For example: sauces (mayonnaise, mustard, ketchup) or beverages (water, cola, lemonade).
| Field | Type | Description |
|---|---|---|
id | string | The ID of the group |
name | string | The name of the group |
min | integer | The minimum number of attributes that can be selected |
max | integer | The maximum number of attributes that can be selected |
collapse | boolean | Whether the group should be collapsed or expanded by default |
attributes | array[Attribute] | The list of attributes for this group |
multiple_selection | boolean | Whether multiple attributes can be selected |
Schema Attribute
Products can be customized in various ways, such as adding mayonnaise, including a beverage, or adding extra meat. Each of these customizations is known as an attribute. Products are not required to have attributes, but each attribute can have a different impact on the price.
| Field | Type | Description |
|---|---|---|
id | string | The ID of the attribute (must be unique) |
name | string | The name of the attribute |
available | boolean | Whether the attribute is available (default: true) |
selected_by_default | boolean | Whether the attribute is selected by default (default: false) |
price | string | The price of the attribute (default: null) |
Check Status V3
GET /api/v3/menu/checkstatus/{trackingCode}
Check the status of the menu update process for a given transaction_id.
Parameters:
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
trackingCode | path | string | Yes | transaction_id returned by upload |
curl -X GET \
'https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/menu/checkstatus/a946a2c7-f4e7-46ac-ae63-8a5497cb0ad9' \
-H 'Authorization: YOUR_API_KEY'import requests
url = "https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/menu/checkstatus/a946a2c7-f4e7-46ac-ae63-8a5497cb0ad9"
response = requests.get(url, headers={"Authorization": "YOUR_API_KEY"})
print(response.json())Response Schema MenuUploadStatus:
{
"transaction_id": "a946a2c7-f4e7-46ac-ae63-8a5497cb0ad9",
"status": "FETCH_MENU_INVALID_PAYLOAD",
"last_updated_at": "2020-03-24T10:03:49.614Z",
"details": [
"Invalid section [\"Menus\"]: Section must contain at least one product"
]
}Possible Status Values:
| Status | Description |
|---|---|
SUCCESS | The menu update process has been successfully completed |
PROCESSING | The menu update process is still ongoing |
FETCH_MENU_INVALID_PAYLOAD | Failed due to an invalid JSON input |
FETCH_MENU_SERVER_ERROR | Server error when fetching menu |
FETCH_MENU_UNAUTHORIZED | Unauthorized |
NOT_PROCESSED | Failed due to incorrect integration configuration |
LIMIT_EXCEEDED | Maximum number of daily menu updates exceeded |
GLOVO_ERROR | Failed due to an error in the Glovo system |
INFO
In case the status indicates an error, the endpoint returns additional information in the details field to help understand the cause of the error.
Modify Product V3
POST /api/v3/item/modify/stores/{storeId}/products/{productId}
Update an individual product in a Glovo store. Allows modification of price and/or availability.
Parameters:
| Parameter | In | Type | Required |
|---|---|---|---|
storeId | path | string | Yes |
productId | path | string | Yes |
Request Body ModifyProduct:
{
"price": 10.0,
"available": true
}| Field | Type | Description |
|---|---|---|
price | number (double) | The new price of the product. If not present or null, will not be updated |
available | boolean | Whether the product is available. If not present or null, will not be updated |
curl -X POST \
'https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/item/modify/stores/partner__001/products/burger1' \
-H 'Authorization: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"price": 10.0, "available": true}'import requests
url = "https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/item/modify/stores/partner__001/products/burger1"
response = requests.post(url, json={"price": 10.0, "available": True}, headers={"Authorization": "YOUR_API_KEY"})Response Schema ModifyProductResult:
{
"id": "burger1",
"name": "Burger Large",
"price": "10.0",
"image_url": "https://server.com/image",
"description": "A large cheeseburger",
"available": true,
"error": null
}Responses: 200 Product updated | 400 Invalid payload | 401 Unauthorized | 500 Server error
Modify Attribute V3
POST /api/v3/item/modify/stores/{storeId}/attributes/{attributeId}
Update an individual attribute in a Glovo store.
Parameters:
| Parameter | In | Type | Required |
|---|---|---|---|
storeId | path | string | Yes |
attributeId | path | string | Yes |
Request Body ModifyAttribute:
{
"price_impact": 1.5,
"available": true
}| Field | Type | Description |
|---|---|---|
price_impact | number (double) | The new price of the attribute. If not present or null, will not be updated |
available | boolean | Whether the attribute is available. If not present or null, will not be updated |
curl -X POST \
'https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/item/modify/stores/partner__001/attributes/side1' \
-H 'Authorization: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"price_impact": 1.5, "available": true}'Response Schema ModifyAttributeResult:
{
"id": "side1",
"name": "French fries",
"selected_by_default": true,
"price": "1.5",
"available": true,
"error": null
}Responses: 200 Attribute updated | 400 Invalid payload | 401 Unauthorized | 500 Server error
Bulk Update V3
POST /api/v3/item/modify/stores/{storeId}/bulk
Bulk update for products and attributes. Asynchronous operation — returns transaction_id.
Parameters:
| Parameter | In | Type | Required |
|---|---|---|---|
storeId | path | string | Yes |
Request Body BulkUpdateItems:
{
"products": [
{
"id": "burger1",
"name": "Burger Large",
"price": 10.0,
"image_url": "https://server.com/image",
"extra_image_urls": [
"https://i.imgur.com/Tsj3NOK.png",
"https://i.imgur.com/Qj5DlEH.png"
],
"restrictions": {
"is_alcoholic": false
},
"available": true
}
],
"attributes": [
{
"id": "side1",
"name": "French fries",
"price_impact": 1.5,
"available": true
}
]
}Schema BulkUpdateItemsProducts
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier of the product within the store |
name | string | Product name |
price | number | Product price |
image_url | string | Main product image URL (HTTPS) |
extra_image_urls | array[string] | Additional image URLs (HTTPS, max 9 — if more are sent, only the first 9 will be processed). Displayed on the product detail page in the same order as in the array, always after the main image |
restrictions | MenuRestrictions | Product restrictions |
available | boolean | Whether the product is available |
Schema MenuRestrictions
| Field | Type | Description |
|---|---|---|
is_alcoholic | boolean | Indicates whether the product is an alcoholic beverage. It will trigger a user flow according to restrictions for stores in Poland and Romania. To activate alcohol restriction, contact the integration team at pos.integrations@appsmart.ro |
Schema BulkUpdateItemsAttributes
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier of the attribute within the store |
name | string | Attribute name |
price_impact | number | Attribute price |
available | boolean | Whether the attribute is available |
curl -X POST \
'https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/item/modify/stores/partner__001/bulk' \
-H 'Authorization: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d @bulk-update.jsonResponse Schema BulkUpdateItemsStatus:
{
"error": null,
"message": null,
"transaction_id": "a946a2c7-f4e7-46ac-ae63-8a5497cb0ad9",
"status": "PARTIALLY_PROCESSED",
"last_updated_at": "2020-03-24T10:03:49.614Z",
"details": [
"Products updated: [11111, 22222]",
"Products not updated: [12345, 56789]",
"Attributes updated: [33333, 44444]",
"Attributes not updated: [67890, 45678]"
]
}Bulk Update Statuses:
| Status | Description |
|---|---|
SUCCESS | All items updated successfully |
PROCESSING | Processing in progress |
PARTIALLY_PROCESSED | Only some items were updated |
NOT_PROCESSED | No items were processed |
GLOVO_ERROR | Glovo system error |
Bulk Update Check Status V3
GET /api/v3/item/modify/checkstatus/bulk/{trackingCode}
Check status for bulk update operation.
Parameters:
| Parameter | In | Type | Required |
|---|---|---|---|
trackingCode | path | string | Yes |
curl -X GET \
'https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/item/modify/checkstatus/bulk/a946a2c7-f4e7-46ac-ae63-8a5497cb0ad9' \
-H 'Authorization: YOUR_API_KEY'Response: BulkUpdateItemsStatus schema (see above)
Update Order Status V3
POST /api/v3/order/stores/orders/status
Allows the update of the order status during different stages of preparation.
Request Body OrderStatusChangeRequestVO:
{
"store_id": "partner__001",
"partner_name": "partner",
"order_id": "616342127",
"status": "ACCEPTED"
}| Field | Type | Description |
|---|---|---|
store_id | string | Store ID |
partner_name | string | Partner name |
order_id | string | Order ID |
status | string | New status (see below) |
Available Statuses:
| Status | Description |
|---|---|
ACCEPTED | The order has been accepted by the store. If you don't accept the order, Glovo will still move forward — acceptance is not required to proceed |
READY_FOR_PICKUP | The order is ready to be picked up by a courier or the customer (only available for orders delivered by Glovo couriers) |
OUT_FOR_DELIVERY | The courier has collected the order and is now delivering to the customer (only available for Marketplace orders) |
PICKED_UP_BY_CUSTOMER | The order has been picked up by the customer (only available for pick-up orders) |
curl -X POST \
'https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/order/stores/orders/status' \
-H 'Authorization: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"store_id":"partner__001","partner_name":"partner","order_id":"616342127","status":"ACCEPTED"}'Responses: 200 Status updated | 400 Invalid payload | 401 Unauthorized | 500 Server error
Order Lifecycle V3
PUT /api/v3/order-lifecycle/integrations/orders/{orderId}/accept/{storeId}
Accept order with optional preparation time.
Parameters:
| Parameter | In | Type | Description |
|---|---|---|---|
orderId | path | string | Unique identifier of the order |
storeId | path | string | Unique identifier of the store |
Request Body:
{
"committedPreparationTime": "2024-02-02T19:20:30Z"
}| Field | Type | Description |
|---|---|---|
committedPreparationTime | string (UTC Timestamp) | Optional. The point in time at which the order is expected to be ready in the store. Used to estimate the courier's arrival at the store more accurately. ISO 8601 format, in UTC: YYYY-MM-DDThh:mm:ssZ. |
Accepted range
The value is compared against the preparation time Glovo estimated for that order. Two separate conditions apply — this is not a symmetric tolerance:
estimated < committed ≤ estimated + 900 seconds- Upper bound — the difference from the estimate may not exceed 900 seconds.
- Lower bound — the value must be strictly greater than the estimate. There is no tolerance here: a value equal to the estimate, or below it even by one second, is rejected.
Adjustment logic that aligns the value to Glovo's estimate produces a rejection. The correct target is strictly above the estimate.
Response codes
| Code | Meaning |
|---|---|
204 | The order was accepted and the preparation time was registered. No content. |
202 | The order was accepted, but the preparation time was not registered: either it was not sent, or it falls outside the accepted range. The response body carries the reason. |
400 | The request body is not a JSON object (for example []). The order is not accepted by this request. |
A rejected value does not affect the order — it stays accepted on both 204 and 202. Handling the two codes separately is recommended, so that the POS shows when a submitted time was not taken up.
The request body is always a JSON object. When no preparation time is submitted, send the empty object {}.
Example 202 response — time outside the range:
{
"invalid-params": [
{
"name": "committedPreparationTime",
"reason": "The difference in seconds between committed preparation time and estimated preparation time is exceeding [900] threshold. committed: [1953], estimated: [900]"
}
],
"title": "Your request parameters are not valid."
}The reason message carries the applied threshold and both compared values. Reading the threshold from the message and logging it is recommended, rather than keeping a fixed value in code.
Example 202 response — time not sent:
A request without committedPreparationTime (body {}) also receives 202, with the reason below. The order is accepted; the response only states that no preparation time was registered. It is not an error and does not call for a new request.
{
"invalid-params": [
{
"name": "committedPreparationTime",
"reason": "Committed preparation time is missing."
}
],
"title": "Your request parameters are not valid."
}The value is final
The preparation time is submitted once, on acceptance. There is no follow-up update operation: the remaining order lifecycle operations take only the identifiers, with no request body, so they cannot carry a revised time.
If preparation takes longer than announced, the only remaining signal is ready_for_pickup, sent when the order is actually ready. Accepting the same order a second time is rejected.
PUT /api/v3/order-lifecycle/integrations/orders/{orderId}/ready_for_pickup/{storeId}
Mark order as ready for pickup.
PUT /api/v3/order-lifecycle/integrations/orders/{orderId}/out_for_delivery/{storeId}
Mark order as out for delivery (Marketplace only).
PUT /api/v3/order-lifecycle/integrations/orders/{orderId}/customer_picked_up/{storeId}
Mark order as picked up by customer.
Scheduling V3 — Temporary Closing
PUT /api/v3/scheduling/stores/{storeId}/closing
Set a temporary closing for the store until a specified future date and time. This will override the normal operating hours.
Request Body TemporaryClosingRequest:
{
"until": "2024-12-20T10:00:00+01:00"
}| Field | Type | Required | Description |
|---|---|---|---|
until | string | Yes | The date and time (with UTC offset) until which the store will be closed. ISO-8601 format |
Responses:
| Status | Description |
|---|---|
204 | Temporary closing set successfully |
400 | Bad Request (invalid payload, date in the past, invalid storeId) |
401 | Unauthorized (invalid API token) |
403 | Forbidden (API token does not have permissions) |
404 | Not Found (store not found) |
500 | Internal Server Error |
GET /api/v3/scheduling/stores/{storeId}/closing
Get the status of the store's active temporary closing, if one exists.
Response Schema TemporaryClosingStatusResponse:
{
"until": "2024-12-20T10:00:00+01:00"
}| Field | Type | Description |
|---|---|---|
until | string (nullable) | The date and time until which the store is closed. null if there is no active closing |
DELETE /api/v3/scheduling/stores/{storeId}/closing
Remove the store's active temporary closing. After removal, the store will follow its regular operating schedule.
INFO
Glovo may return 204 even if there is no active closing to remove.
curl -X PUT \
'https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/scheduling/stores/partner__001/closing' \
-H 'Authorization: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"until": "2024-12-20T10:00:00+01:00"}'curl -X GET \
'https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/scheduling/stores/partner__001/closing' \
-H 'Authorization: YOUR_API_KEY'curl -X DELETE \
'https://prod.store-management.glovo.alb.app.onlineservice.io/api/v3/scheduling/stores/partner__001/closing' \
-H 'Authorization: YOUR_API_KEY'