Si lo que quieres es que un agente de IA gestione el menú conversando, eso es el servidor MCP (https://delimenu.co/api/mcp), que usa las mismas operaciones.
Se puede llamar directamente desde el navegador (CORS abierto) y está en caché en el borde: cada cambio que hagas en el panel, por la API o con un agente la refresca en segundos. Si el restaurante no tiene plan activo, responde 403 con solo su nombre, igual que la página pública.
Restaurants
The restaurants of the account the key belongs to.
get/restaurantsrequiere menu:readlistRestaurants
List the restaurants of the account
Call this first; every other endpoint takes one of these by identifier or id.
Ejemplo
curl -X GET "https://delimenu.co/api/v1/restaurants" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Respuesta 200
{
"restaurants": [
{
"id": "aR3kX9pLm2QzT7vN4bYc",
"identifier": "pizzeria-roma",
"name": "Pizzería Roma",
"currency": "COP",
"type": "whatsapp",
"phone": "+573001234567",
"address": "Calle 10 # 5-20, Bogotá",
"menu_url": "https://delimenu.co/pizzeria-roma",
"logo_url": "https://firebasestorage.googleapis.com/v0/b/example/o/logo_512x512.png?alt=media",
"banner_url": null,
"trial_active": false
}
]
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
restaurants* | object[] | |
id* | string | |
identifier* | string | |
name* | string | |
currency* | string | ISO 4217 code every price is in |
type* | "whatsapp" | "read_only" | "whatsapp" takes orders by WhatsApp; "read_only" only shows the menu |
phone* | string | null | WhatsApp number in E.164, when ordering is enabled |
address* | string | null | |
menu_url* | string | |
logo_url* | string | null | |
banner_url* | string | null | |
trial_active* | boolean | |
Errores
401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
get/restaurants/{ref}requiere menu:readgetRestaurant
Get a restaurant
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
Ejemplo
curl -X GET "https://delimenu.co/api/v1/restaurants/pizzeria-roma" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Respuesta 200
{
"restaurant": {
"id": "aR3kX9pLm2QzT7vN4bYc",
"identifier": "pizzeria-roma",
"name": "Pizzería Roma",
"currency": "COP",
"type": "whatsapp",
"phone": "+573001234567",
"address": "Calle 10 # 5-20, Bogotá",
"menu_url": "https://delimenu.co/pizzeria-roma",
"logo_url": "https://firebasestorage.googleapis.com/v0/b/example/o/logo_512x512.png?alt=media",
"banner_url": null,
"trial_active": false
}
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
restaurant* | object | |
id* | string | |
identifier* | string | |
name* | string | |
currency* | string | ISO 4217 code every price is in |
type* | "whatsapp" | "read_only" | "whatsapp" takes orders by WhatsApp; "read_only" only shows the menu |
phone* | string | null | WhatsApp number in E.164, when ordering is enabled |
address* | string | null | |
menu_url* | string | |
logo_url* | string | null | |
banner_url* | string | null | |
trial_active* | boolean | |
Errores
401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
patch/restaurants/{ref}requiere menu:writeupdateRestaurant
Update a restaurant
Changes only the fields given: name, WhatsApp phone, address, currency or type. Changing the currency converts no prices. The identifier has its own endpoint.
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
Cuerpo (JSON)
| Campo | Tipo | Descripción |
|---|
name | string | hasta 50 caracteres |
phone | string | WhatsApp number that receives orders, in E.164 format (+573001234567) |
address | string | Street address shown on the menu. Empty string removes it.hasta 65 caracteres |
currency | string | ISO 4217 code every price is shown in. Changing it converts nothing. |
type | "whatsapp" | "read_only" | "whatsapp" takes orders by WhatsApp; "read_only" only shows the menu |
Ejemplo
curl -X PATCH "https://delimenu.co/api/v1/restaurants/pizzeria-roma" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"phone":"+573009876543","address":"Carrera 7 # 45-10, Bogotá"}'
Respuesta 200
{
"restaurant": {
"id": "aR3kX9pLm2QzT7vN4bYc",
"identifier": "pizzeria-roma",
"name": "Pizzería Roma",
"currency": "COP",
"type": "whatsapp",
"phone": "+573009876543",
"address": "Carrera 7 # 45-10, Bogotá",
"menu_url": "https://delimenu.co/pizzeria-roma",
"logo_url": "https://firebasestorage.googleapis.com/v0/b/example/o/logo_512x512.png?alt=media",
"banner_url": null,
"trial_active": false
}
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
restaurant* | object | |
id* | string | |
identifier* | string | |
name* | string | |
currency* | string | ISO 4217 code every price is in |
type* | "whatsapp" | "read_only" | "whatsapp" takes orders by WhatsApp; "read_only" only shows the menu |
phone* | string | null | WhatsApp number in E.164, when ordering is enabled |
address* | string | null | |
menu_url* | string | |
logo_url* | string | null | |
banner_url* | string | null | |
trial_active* | boolean | |
Errores
400 VALIDATION — a field is missing or malformed; `issues` names it401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
put/restaurants/{ref}/identifierrequiere menu:writeupdateRestaurantIdentifier
Change the public URL
Changes the slug of the menu (delimenu.co/{identifier}). The old URL stops working immediately; printed QR codes keep working because they point at the restaurant id.
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
Cuerpo (JSON)
| Campo | Tipo | Descripción |
|---|
identifier* | string | The new public slug: lowercase letters, digits, dots, hyphens and underscores, e.g. "pizzeria-roma"hasta 50 caracteres |
Ejemplo
curl -X PUT "https://delimenu.co/api/v1/restaurants/pizzeria-roma/identifier" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"identifier":"pizzeria-roma-chapinero"}'
Respuesta 200
{
"restaurant": {
"id": "aR3kX9pLm2QzT7vN4bYc",
"identifier": "pizzeria-roma-chapinero",
"name": "Pizzería Roma",
"currency": "COP",
"type": "whatsapp",
"phone": "+573001234567",
"address": "Calle 10 # 5-20, Bogotá",
"menu_url": "https://delimenu.co/pizzeria-roma-chapinero",
"logo_url": "https://firebasestorage.googleapis.com/v0/b/example/o/logo_512x512.png?alt=media",
"banner_url": null,
"trial_active": false
}
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
restaurant* | object | |
id* | string | |
identifier* | string | |
name* | string | |
currency* | string | ISO 4217 code every price is in |
type* | "whatsapp" | "read_only" | "whatsapp" takes orders by WhatsApp; "read_only" only shows the menu |
phone* | string | null | WhatsApp number in E.164, when ordering is enabled |
address* | string | null | |
menu_url* | string | |
logo_url* | string | null | |
banner_url* | string | null | |
trial_active* | boolean | |
Errores
400 VALIDATION — a field is missing or malformed; `issues` names it401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it409 CONFLICT — the identifier is already taken500 INTERNAL — something failed on our side; retry in a moment
Categories
get/restaurants/{ref}/categoriesrequiere menu:readlistCategories
List the categories
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
Ejemplo
curl -X GET "https://delimenu.co/api/v1/restaurants/pizzeria-roma/categories" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Respuesta 200
{
"categories": [
{
"id": "k3Qm8vXb2LpN7wRt1YaZ",
"name": "Pizzas",
"position": 1
},
{
"id": "c7Wd2Bn5Kq9Xr4Ms8Lt1",
"name": "Bebidas",
"position": 2
}
]
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
categories* | object[] | |
id* | string | |
name* | string | |
position* | integer | min -9007199254740991 · max 9007199254740991 |
Errores
401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
post/restaurants/{ref}/categoriesrequiere menu:writecreateCategory
Create a category
Adds a category at the end of the menu.
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
Cuerpo (JSON)
| Campo | Tipo | Descripción |
|---|
name* | string | Category namehasta 50 caracteres |
Ejemplo
curl -X POST "https://delimenu.co/api/v1/restaurants/pizzeria-roma/categories" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"name":"Postres"}'
Respuesta 201
{
"category": {
"id": "d4Fg6Hj8Kl0Zx2Cv4Bn6",
"name": "Postres"
}
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
category* | object | |
id* | string | |
name* | string | |
Errores
400 VALIDATION — a field is missing or malformed; `issues` names it401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it409 CONFLICT — a category with that name already exists500 INTERNAL — something failed on our side; retry in a moment
put/restaurants/{ref}/category-orderrequiere menu:writereorderCategories
Reorder the categories
Sets the display order. Pass every category id exactly once, in the new order.
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
Cuerpo (JSON)
| Campo | Tipo | Descripción |
|---|
category_ids* | string[] | Every category id exactly once, in the new display order |
Ejemplo
curl -X PUT "https://delimenu.co/api/v1/restaurants/pizzeria-roma/category-order" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"category_ids":["c7Wd2Bn5Kq9Xr4Ms8Lt1","k3Qm8vXb2LpN7wRt1YaZ"]}'
Respuesta 200
{
"order_categories": [
"c7Wd2Bn5Kq9Xr4Ms8Lt1",
"k3Qm8vXb2LpN7wRt1YaZ"
]
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
order_categories* | string[] | |
Errores
400 VALIDATION — a field is missing or malformed; `issues` names it401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
patch/restaurants/{ref}/categories/{id}requiere menu:writeupdateCategory
Rename a category
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
id* | ruta | The category id, from GET /restaurants/{ref}/categories |
Cuerpo (JSON)
| Campo | Tipo | Descripción |
|---|
name* | string | Category namehasta 50 caracteres |
Ejemplo
curl -X PATCH "https://delimenu.co/api/v1/restaurants/pizzeria-roma/categories/k3Qm8vXb2LpN7wRt1YaZ" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"name":"Pizzas artesanales"}'
Respuesta 200
{
"category": {
"id": "k3Qm8vXb2LpN7wRt1YaZ",
"name": "Pizzas artesanales"
}
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
category* | object | |
id* | string | |
name* | string | |
Errores
400 VALIDATION — a field is missing or malformed; `issues` names it401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
delete/restaurants/{ref}/categories/{id}requiere menu:writedeleteCategory
Delete a category
Refused with 409 while the category still has products, unless delete_products is true, in which case the products are deleted too.
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
id* | ruta | The category id, from GET /restaurants/{ref}/categories |
delete_products | query | Delete the products in the category too. Without it a non-empty category is refused with 409. |
Ejemplo
curl -X DELETE "https://delimenu.co/api/v1/restaurants/pizzeria-roma/categories/k3Qm8vXb2LpN7wRt1YaZ?delete_products=true" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Respuesta 200
{
"deleted": "k3Qm8vXb2LpN7wRt1YaZ",
"deleted_products": 3
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
deleted* | string | |
deleted_products* | integer | min -9007199254740991 · max 9007199254740991 |
Errores
400 VALIDATION — a field is missing or malformed; `issues` names it401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it409 CONFLICT — the category still has products500 INTERNAL — something failed on our side; retry in a moment
put/restaurants/{ref}/categories/{id}/product-orderrequiere menu:writereorderProducts
Reorder the products of a category
Pass every product id of that category exactly once, in the new order.
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
id* | ruta | The category id, from GET /restaurants/{ref}/categories |
Cuerpo (JSON)
| Campo | Tipo | Descripción |
|---|
product_ids* | string[] | Every product id of the category exactly once, in the new display order |
Ejemplo
curl -X PUT "https://delimenu.co/api/v1/restaurants/pizzeria-roma/categories/k3Qm8vXb2LpN7wRt1YaZ/product-order" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"product_ids":["q2Jk5Lm8Np1Qr4St7Uv0","p9Hs4TqL2mNc8VbX6Rdy"]}'
Respuesta 200
{
"category_id": "k3Qm8vXb2LpN7wRt1YaZ",
"order_products": [
"q2Jk5Lm8Np1Qr4St7Uv0",
"p9Hs4TqL2mNc8VbX6Rdy"
]
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
category_id* | string | |
order_products* | string[] | |
Errores
400 VALIDATION — a field is missing or malformed; `issues` names it401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
Products
get/restaurants/{ref}/productsrequiere menu:readlistProducts
List or search the products
Every product, hidden ones included and flagged. With q, only those whose name or description contains the text.
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
q | query | Only products whose name or description contains this text (accent- and case-insensitive)hasta 100 caracteres |
Ejemplo
curl -X GET "https://delimenu.co/api/v1/restaurants/pizzeria-roma/products?q=margarita" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Respuesta 200
{
"products": [
{
"id": "p9Hs4TqL2mNc8VbX6Rdy",
"category_id": "k3Qm8vXb2LpN7wRt1YaZ",
"name": "Pizza Margarita",
"price": 32000,
"original_price": 38000,
"description": "Tomate, mozzarella y albahaca fresca",
"available": true,
"hidden": false,
"has_image": true,
"image_url": "https://firebasestorage.googleapis.com/v0/b/example/o/margarita_1080x1080.jpg?alt=media",
"variants": [
{
"id": "26fed9f6-2e3b-4310-b899-5641bf98e2f0",
"name": "Tamaño",
"min_selections": 1,
"max_selections": 1,
"options": [
{
"id": "5c4f8896-06a3-4482-99d1-185a909d0415",
"name": "Personal",
"price": 0,
"show": true
},
{
"id": "b1e0c4d2-7f3a-4c8e-9d21-0a5f6e7b8c9d",
"name": "Familiar",
"price": 12000,
"show": true
}
]
}
]
}
],
"count": 1
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
products* | object[] | |
id* | string | |
category_id* | string | |
name* | string | |
price* | number | Major units in the restaurant's currency |
original_price | number | Present while the product is on promotion |
description | string | |
available* | boolean | false renders "Sin stock" |
hidden* | boolean | true keeps it off the public menu |
has_image* | boolean | |
image_url | string | |
variants* | object[] | |
id* | string | |
name* | string | |
min_selections* | integer | min -9007199254740991 · max 9007199254740991 |
max_selections* | integer | 0 is no limitmin -9007199254740991 · max 9007199254740991 |
max_per_option | integer | min -9007199254740991 · max 9007199254740991 |
options* | object[] | |
id* | string | |
name* | string | |
price* | number | Extra charge on top of the product price |
show* | boolean | |
count* | integer | min -9007199254740991 · max 9007199254740991 |
Errores
400 VALIDATION — a field is missing or malformed; `issues` names it401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
post/restaurants/{ref}/productsrequiere menu:writecreateProduct
Create a product
Adds a product to a category, at the end. Price is in the restaurant's currency, major units. Variants are optional choices (sizes, extras) with their own option prices.
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
Cuerpo (JSON)
| Campo | Tipo | Descripción |
|---|
category_id* | string | The category the product belongs to (from get_menu)hasta 128 caracteres |
name* | string | Product namehasta 50 caracteres |
price* | number | Price in the restaurant's currency, in major units (12500 for COP $12.000, 5.99 for USD $5.99). Never cents.min 0 |
description | string | Optional description. Pass an empty string to remove it.hasta 3000 caracteres |
original_price | number | null | The price before a promotion. Must be greater than price; the menu shows it struck through. Pass null to end the promotion.min 0 |
available | boolean | false shows the product as "Sin stock": visible but not orderable. Default true. |
hidden | boolean | true keeps the product off the public menu entirely. Default false. |
variants | object[] | Choices the diner makes (sizes, extras). Replaces the whole list when provided. |
name* | string | Variant name, e.g. "Tamaño" or "Adiciones"hasta 50 caracteres |
min_selections | integer | Options the diner must pick. 0 makes the variant optional.min 0 · max 9007199254740991 · por defecto 0 |
max_selections | integer | Options the diner may pick. 0 is no limit; 1 renders a single choice.min 0 · max 9007199254740991 · por defecto 0 |
max_per_option | integer | How many times one option may be repeated. Omit or 0 for no limit.min 0 · max 9007199254740991 |
options* | object[] | |
name* | string | Option name, e.g. "Grande"hasta 50 caracteres |
price | number | Extra charge for this option on top of the product price. 0 when it costs nothing.min 0 · por defecto 0 |
show | boolean | false hides the option from diners without deleting itpor defecto true |
Ejemplo
curl -X POST "https://delimenu.co/api/v1/restaurants/pizzeria-roma/products" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"category_id":"k3Qm8vXb2LpN7wRt1YaZ","name":"Pizza Margarita","price":32000,"description":"Tomate, mozzarella y albahaca fresca","variants":[{"name":"Tamaño","min_selections":1,"max_selections":1,"options":[{"name":"Personal","price":0},{"name":"Familiar","price":12000}]}]}'
Respuesta 201
{
"product": {
"id": "p9Hs4TqL2mNc8VbX6Rdy",
"category_id": "k3Qm8vXb2LpN7wRt1YaZ",
"name": "Pizza Margarita",
"price": 32000,
"description": "Tomate, mozzarella y albahaca fresca",
"available": true,
"hidden": false,
"has_image": true,
"image_url": "https://firebasestorage.googleapis.com/v0/b/example/o/margarita_1080x1080.jpg?alt=media",
"variants": [
{
"id": "26fed9f6-2e3b-4310-b899-5641bf98e2f0",
"name": "Tamaño",
"min_selections": 1,
"max_selections": 1,
"options": [
{
"id": "5c4f8896-06a3-4482-99d1-185a909d0415",
"name": "Personal",
"price": 0,
"show": true
},
{
"id": "b1e0c4d2-7f3a-4c8e-9d21-0a5f6e7b8c9d",
"name": "Familiar",
"price": 12000,
"show": true
}
]
}
]
}
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
product* | object | |
id* | string | |
category_id* | string | |
name* | string | |
price* | number | Major units in the restaurant's currency |
original_price | number | Present while the product is on promotion |
description | string | |
available* | boolean | false renders "Sin stock" |
hidden* | boolean | true keeps it off the public menu |
has_image* | boolean | |
image_url | string | |
variants* | object[] | |
id* | string | |
name* | string | |
min_selections* | integer | min -9007199254740991 · max 9007199254740991 |
max_selections* | integer | 0 is no limitmin -9007199254740991 · max 9007199254740991 |
max_per_option | integer | min -9007199254740991 · max 9007199254740991 |
options* | object[] | |
id* | string | |
name* | string | |
price* | number | Extra charge on top of the product price |
show* | boolean | |
Errores
400 VALIDATION — a field is missing or malformed; `issues` names it401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
patch/restaurants/{ref}/productsrequiere menu:writebulkUpdateProducts
Update many products
Applies a patch to up to 50 products in one write — for "raise every price 10%" or "mark these as out of stock". Same fields as updating one product.
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
Cuerpo (JSON)
| Campo | Tipo | Descripción |
|---|
updates* | object[] | Up to 50 products, each with only the fields to change |
product_id* | string | hasta 128 caracteres |
changes* | object | |
category_id | string | Move the product to another categoryhasta 128 caracteres |
name | string | Product namehasta 50 caracteres |
price | number | Price in the restaurant's currency, in major units (12500 for COP $12.000, 5.99 for USD $5.99). Never cents.min 0 |
description | string | Optional description. Pass an empty string to remove it.hasta 3000 caracteres |
original_price | number | null | The price before a promotion. Must be greater than price; the menu shows it struck through. Pass null to end the promotion.min 0 |
available | boolean | false shows the product as "Sin stock": visible but not orderable. Default true. |
hidden | boolean | true keeps the product off the public menu entirely. Default false. |
variants | object[] | Choices the diner makes (sizes, extras). Replaces the whole list when provided. |
name* | string | Variant name, e.g. "Tamaño" or "Adiciones"hasta 50 caracteres |
min_selections | integer | Options the diner must pick. 0 makes the variant optional.min 0 · max 9007199254740991 · por defecto 0 |
max_selections | integer | Options the diner may pick. 0 is no limit; 1 renders a single choice.min 0 · max 9007199254740991 · por defecto 0 |
max_per_option | integer | How many times one option may be repeated. Omit or 0 for no limit.min 0 · max 9007199254740991 |
options* | object[] | |
Ejemplo
curl -X PATCH "https://delimenu.co/api/v1/restaurants/pizzeria-roma/products" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"updates":[{"product_id":"p9Hs4TqL2mNc8VbX6Rdy","changes":{"price":35000}},{"product_id":"q2Jk5Lm8Np1Qr4St7Uv0","changes":{"available":false}}]}'
Respuesta 200
{
"updated": 2
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
updated* | integer | min -9007199254740991 · max 9007199254740991 |
Errores
400 VALIDATION — a field is missing or malformed; `issues` names it401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
get/restaurants/{ref}/products/{id}requiere menu:readgetProduct
Get a product
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
id* | ruta | The product id, from GET /restaurants/{ref}/products |
Ejemplo
curl -X GET "https://delimenu.co/api/v1/restaurants/pizzeria-roma/products/p9Hs4TqL2mNc8VbX6Rdy" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Respuesta 200
{
"product": {
"id": "p9Hs4TqL2mNc8VbX6Rdy",
"category_id": "k3Qm8vXb2LpN7wRt1YaZ",
"name": "Pizza Margarita",
"price": 32000,
"original_price": 38000,
"description": "Tomate, mozzarella y albahaca fresca",
"available": true,
"hidden": false,
"has_image": true,
"image_url": "https://firebasestorage.googleapis.com/v0/b/example/o/margarita_1080x1080.jpg?alt=media",
"variants": [
{
"id": "26fed9f6-2e3b-4310-b899-5641bf98e2f0",
"name": "Tamaño",
"min_selections": 1,
"max_selections": 1,
"options": [
{
"id": "5c4f8896-06a3-4482-99d1-185a909d0415",
"name": "Personal",
"price": 0,
"show": true
},
{
"id": "b1e0c4d2-7f3a-4c8e-9d21-0a5f6e7b8c9d",
"name": "Familiar",
"price": 12000,
"show": true
}
]
}
]
}
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
product* | object | |
id* | string | |
category_id* | string | |
name* | string | |
price* | number | Major units in the restaurant's currency |
original_price | number | Present while the product is on promotion |
description | string | |
available* | boolean | false renders "Sin stock" |
hidden* | boolean | true keeps it off the public menu |
has_image* | boolean | |
image_url | string | |
variants* | object[] | |
id* | string | |
name* | string | |
min_selections* | integer | min -9007199254740991 · max 9007199254740991 |
max_selections* | integer | 0 is no limitmin -9007199254740991 · max 9007199254740991 |
max_per_option | integer | min -9007199254740991 · max 9007199254740991 |
options* | object[] | |
id* | string | |
name* | string | |
price* | number | Extra charge on top of the product price |
show* | boolean | |
Errores
401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
patch/restaurants/{ref}/products/{id}requiere menu:writeupdateProduct
Update a product
Changes only the fields given: name, price, description, original_price (promotion), available, hidden, variants (replaces all) or category_id (moves it). Raising price above an existing original_price ends the promotion.
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
id* | ruta | The product id, from GET /restaurants/{ref}/products |
Cuerpo (JSON)
| Campo | Tipo | Descripción |
|---|
category_id | string | Move the product to another categoryhasta 128 caracteres |
name | string | Product namehasta 50 caracteres |
price | number | Price in the restaurant's currency, in major units (12500 for COP $12.000, 5.99 for USD $5.99). Never cents.min 0 |
description | string | Optional description. Pass an empty string to remove it.hasta 3000 caracteres |
original_price | number | null | The price before a promotion. Must be greater than price; the menu shows it struck through. Pass null to end the promotion.min 0 |
available | boolean | false shows the product as "Sin stock": visible but not orderable. Default true. |
hidden | boolean | true keeps the product off the public menu entirely. Default false. |
variants | object[] | Choices the diner makes (sizes, extras). Replaces the whole list when provided. |
name* | string | Variant name, e.g. "Tamaño" or "Adiciones"hasta 50 caracteres |
min_selections | integer | Options the diner must pick. 0 makes the variant optional.min 0 · max 9007199254740991 · por defecto 0 |
max_selections | integer | Options the diner may pick. 0 is no limit; 1 renders a single choice.min 0 · max 9007199254740991 · por defecto 0 |
max_per_option | integer | How many times one option may be repeated. Omit or 0 for no limit.min 0 · max 9007199254740991 |
options* | object[] | |
name* | string | Option name, e.g. "Grande"hasta 50 caracteres |
price | number | Extra charge for this option on top of the product price. 0 when it costs nothing.min 0 · por defecto 0 |
show | boolean | false hides the option from diners without deleting itpor defecto true |
Ejemplo
curl -X PATCH "https://delimenu.co/api/v1/restaurants/pizzeria-roma/products/p9Hs4TqL2mNc8VbX6Rdy" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"price":30000,"original_price":38000,"available":true}'
Respuesta 200
{
"product": {
"id": "p9Hs4TqL2mNc8VbX6Rdy",
"category_id": "k3Qm8vXb2LpN7wRt1YaZ",
"name": "Pizza Margarita",
"price": 30000,
"original_price": 38000,
"description": "Tomate, mozzarella y albahaca fresca",
"available": true,
"hidden": false,
"has_image": true,
"image_url": "https://firebasestorage.googleapis.com/v0/b/example/o/margarita_1080x1080.jpg?alt=media",
"variants": [
{
"id": "26fed9f6-2e3b-4310-b899-5641bf98e2f0",
"name": "Tamaño",
"min_selections": 1,
"max_selections": 1,
"options": [
{
"id": "5c4f8896-06a3-4482-99d1-185a909d0415",
"name": "Personal",
"price": 0,
"show": true
},
{
"id": "b1e0c4d2-7f3a-4c8e-9d21-0a5f6e7b8c9d",
"name": "Familiar",
"price": 12000,
"show": true
}
]
}
]
}
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
product* | object | |
id* | string | |
category_id* | string | |
name* | string | |
price* | number | Major units in the restaurant's currency |
original_price | number | Present while the product is on promotion |
description | string | |
available* | boolean | false renders "Sin stock" |
hidden* | boolean | true keeps it off the public menu |
has_image* | boolean | |
image_url | string | |
variants* | object[] | |
id* | string | |
name* | string | |
min_selections* | integer | min -9007199254740991 · max 9007199254740991 |
max_selections* | integer | 0 is no limitmin -9007199254740991 · max 9007199254740991 |
max_per_option | integer | min -9007199254740991 · max 9007199254740991 |
options* | object[] | |
id* | string | |
name* | string | |
price* | number | Extra charge on top of the product price |
show* | boolean | |
Errores
400 VALIDATION — a field is missing or malformed; `issues` names it401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
delete/restaurants/{ref}/products/{id}requiere menu:writedeleteProduct
Delete a product
Permanent, photo included. Prefer hidden: true when the owner may want it back.
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
id* | ruta | The product id, from GET /restaurants/{ref}/products |
Ejemplo
curl -X DELETE "https://delimenu.co/api/v1/restaurants/pizzeria-roma/products/p9Hs4TqL2mNc8VbX6Rdy" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Respuesta 200
{
"deleted": "p9Hs4TqL2mNc8VbX6Rdy"
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
deleted* | string | |
Errores
401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
Images
Photos, logo and banner from a public https URL (JPG, PNG or WEBP, up to 5 MB).
put/restaurants/{ref}/images/{kind}requiere menu:writesetRestaurantImage
Set the logo or the banner
Downloads the image at a public https URL and sets it as the logo or the banner, replacing the current one. Takes a few seconds while the image is optimised.
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
kind* | ruta | "logo" is shown at 512×512; "banner" is the header image, 1080×1080 max"logo" | "banner" |
Cuerpo (JSON)
| Campo | Tipo | Descripción |
|---|
image_url* | string | Public https URL of a JPG, PNG or WEBP image up to 5 MBhasta 2048 caracteres |
Ejemplo
curl -X PUT "https://delimenu.co/api/v1/restaurants/pizzeria-roma/images/logo" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"image_url":"https://example.com/logo.png"}'
Respuesta 200
{
"restaurant": {
"id": "aR3kX9pLm2QzT7vN4bYc",
"identifier": "pizzeria-roma",
"name": "Pizzería Roma",
"currency": "COP",
"type": "whatsapp",
"phone": "+573001234567",
"address": "Calle 10 # 5-20, Bogotá",
"menu_url": "https://delimenu.co/pizzeria-roma",
"logo_url": "https://firebasestorage.googleapis.com/v0/b/example/o/logo_512x512.png?alt=media",
"banner_url": null,
"trial_active": false
}
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
restaurant* | object | |
id* | string | |
identifier* | string | |
name* | string | |
currency* | string | ISO 4217 code every price is in |
type* | "whatsapp" | "read_only" | "whatsapp" takes orders by WhatsApp; "read_only" only shows the menu |
phone* | string | null | WhatsApp number in E.164, when ordering is enabled |
address* | string | null | |
menu_url* | string | |
logo_url* | string | null | |
banner_url* | string | null | |
trial_active* | boolean | |
Errores
400 VALIDATION — a field is missing or malformed; `issues` names it401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
delete/restaurants/{ref}/images/{kind}requiere menu:writeremoveRestaurantImage
Remove the logo or the banner
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
kind* | ruta | "logo" is shown at 512×512; "banner" is the header image, 1080×1080 max"logo" | "banner" |
Ejemplo
curl -X DELETE "https://delimenu.co/api/v1/restaurants/pizzeria-roma/images/logo" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Respuesta 200
{
"restaurant": {
"id": "aR3kX9pLm2QzT7vN4bYc",
"identifier": "pizzeria-roma",
"name": "Pizzería Roma",
"currency": "COP",
"type": "whatsapp",
"phone": "+573001234567",
"address": "Calle 10 # 5-20, Bogotá",
"menu_url": "https://delimenu.co/pizzeria-roma",
"logo_url": null,
"banner_url": null,
"trial_active": false
}
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
restaurant* | object | |
id* | string | |
identifier* | string | |
name* | string | |
currency* | string | ISO 4217 code every price is in |
type* | "whatsapp" | "read_only" | "whatsapp" takes orders by WhatsApp; "read_only" only shows the menu |
phone* | string | null | WhatsApp number in E.164, when ordering is enabled |
address* | string | null | |
menu_url* | string | |
logo_url* | string | null | |
banner_url* | string | null | |
trial_active* | boolean | |
Errores
401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
put/restaurants/{ref}/products/{id}/imagerequiere menu:writesetProductImage
Set the product photo
Downloads the image at a public https URL and makes it the product photo, replacing the current one. Takes a few seconds while the image is optimised.
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
id* | ruta | The product id, from GET /restaurants/{ref}/products |
Cuerpo (JSON)
| Campo | Tipo | Descripción |
|---|
image_url* | string | Public https URL of a JPG, PNG or WEBP image up to 5 MBhasta 2048 caracteres |
Ejemplo
curl -X PUT "https://delimenu.co/api/v1/restaurants/pizzeria-roma/products/p9Hs4TqL2mNc8VbX6Rdy/image" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"image_url":"https://example.com/fotos/margarita.jpg"}'
Respuesta 200
{
"product": {
"id": "p9Hs4TqL2mNc8VbX6Rdy",
"category_id": "k3Qm8vXb2LpN7wRt1YaZ",
"name": "Pizza Margarita",
"price": 32000,
"original_price": 38000,
"description": "Tomate, mozzarella y albahaca fresca",
"available": true,
"hidden": false,
"has_image": true,
"image_url": "https://firebasestorage.googleapis.com/v0/b/example/o/margarita_1080x1080.jpg?alt=media",
"variants": [
{
"id": "26fed9f6-2e3b-4310-b899-5641bf98e2f0",
"name": "Tamaño",
"min_selections": 1,
"max_selections": 1,
"options": [
{
"id": "5c4f8896-06a3-4482-99d1-185a909d0415",
"name": "Personal",
"price": 0,
"show": true
},
{
"id": "b1e0c4d2-7f3a-4c8e-9d21-0a5f6e7b8c9d",
"name": "Familiar",
"price": 12000,
"show": true
}
]
}
]
}
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
product* | object | |
id* | string | |
category_id* | string | |
name* | string | |
price* | number | Major units in the restaurant's currency |
original_price | number | Present while the product is on promotion |
description | string | |
available* | boolean | false renders "Sin stock" |
hidden* | boolean | true keeps it off the public menu |
has_image* | boolean | |
image_url | string | |
variants* | object[] | |
id* | string | |
name* | string | |
min_selections* | integer | min -9007199254740991 · max 9007199254740991 |
max_selections* | integer | 0 is no limitmin -9007199254740991 · max 9007199254740991 |
max_per_option | integer | min -9007199254740991 · max 9007199254740991 |
options* | object[] | |
id* | string | |
name* | string | |
price* | number | Extra charge on top of the product price |
show* | boolean | |
Errores
400 VALIDATION — a field is missing or malformed; `issues` names it401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment
delete/restaurants/{ref}/products/{id}/imagerequiere menu:writeremoveProductImage
Remove the product photo
Parámetros
| Nombre | Dónde | Descripción |
|---|
ref* | ruta | The restaurant identifier (the slug in its public URL, e.g. "pizzeria-roma") or its id, as returned by GET /restaurants |
id* | ruta | The product id, from GET /restaurants/{ref}/products |
Ejemplo
curl -X DELETE "https://delimenu.co/api/v1/restaurants/pizzeria-roma/products/p9Hs4TqL2mNc8VbX6Rdy/image" \
-H "Authorization: Bearer dmk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Respuesta 200
{
"product_id": "p9Hs4TqL2mNc8VbX6Rdy",
"has_image": false
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|
product_id* | string | |
has_image* | false | |
Errores
401 UNAUTHORIZED — the key is missing, unknown or revoked402 NOT_PREMIUM — the restaurant has no active subscription or trial403 FORBIDDEN — the key lacks the scope this endpoint needs404 NOT_FOUND — no such restaurant in this account, or no such item in it500 INTERNAL — something failed on our side; retry in a moment