MCP Server
The OlaClick MCP (Model Context Protocol) Server allows AI agents and MCP-compatible clients to interact with the OlaClick Public API. Connect your AI assistant to OlaClick and query orders, clients, and product sales data using natural language.
What is MCP?
Model Context Protocol is an open standard that enables AI assistants (like Claude, Cursor, or any MCP-compatible client) to securely interact with external APIs through a standardized interface. Instead of manually crafting API calls, your AI assistant can use OlaClick tools directly.
The MCP server no longer just reads your restaurant's data — it can operate the whole stack: create an order and drive it through its lifecycle (add items, register payments and discounts, apply coupons, change status, cancel it), quote delivery prices before creating an order, run promotions and coupons end to end (create, update, delete), manage webhook subscriptions (create, update, delete), extend the menu (create products and variants, create and update modifiers, sync modifier categories), coordinate logistics (assign a rider, update delivery status), manage clients and their delivery addresses (create, update, list, delete), check food-app store status, and manage connector connections.
Two ways to authenticate
- OAuth (recommended) — for Claude.ai, Claude Desktop, Claude Code, ChatGPT, and any MCP client that supports OAuth 2.1. No API key to generate or paste: you sign in with your OlaClick panel account and authorize the connector for the branch you're logged into. Only Admin or Manager users can authorize a connector.
- API key — for local/stdio setups and clients without OAuth support. You generate a key from the panel and pass it yourself (header or env var).
Both paths reach the same tools and are scoped the same way (see Permissions (scopes)).
Available Tools
The OlaClick MCP server exposes the tools below, grouped by domain. Kind is derived from the underlying HTTP method: read (GET) never changes data, write (POST/PUT/PATCH) creates or updates it, and destructive (DELETE) removes or cancels something — see Write tools: how they behave.
Orders
| Tool | What it does | Required scope | Kind |
|---|---|---|---|
get_orders | Retrieve orders with filters (status, service type, source, dates) | orders:read | read |
get_order | Get a single order by UUID: items, payments, discounts, status | orders:read | read |
list_tables | List zones and their tables, for a valid table_id on create_order | orders:read | read |
get_products_sold | Product sales statistics (top sellers, quantities, revenue) | orders:read | read |
create_order | Create an order (a draft by default) | orders:write | write |
update_order | Edit basic fields of an order created through the API | orders:write | write |
update_order_status | Advance an order's status, including confirming a draft | orders:write | write |
cancel_order | Cancel an order created through the API | orders:write | write |
add_order_combos | Add one or more items to an order | orders:write | write |
remove_order_combo | Cancel one item of an order | orders:write | destructive |
add_order_payment | Register a payment against an order | orders:write | write |
remove_order_payment | Cancel one payment of an order | orders:write | destructive |
add_order_discount | Apply a manual discount to an order | orders:write | write |
remove_order_discount | Remove a discount (or a coupon) from an order | orders:write | destructive |
apply_order_coupon | Redeem a coupon code on an order | orders:write | write |
Promotions
| Tool | What it does | Required scope | Kind |
|---|---|---|---|
get_active_promotions | Promotions redeemable right now, filterable by service type and applicability | promotions:read | read |
list_promotions | Every promotion currently valid (in range, published, redemptions left) | promotions:read | read |
get_promotion | Get a single promotion (coupon) by UUID | promotions:read | read |
create_promotion | Create a promotion: code, discount, eligibility rules | promotions:write | write |
update_promotion | Partially update a promotion (can set a field, not clear it) | promotions:write | write |
delete_promotion | Delete a promotion — cannot be undone | promotions:write | destructive |
Webhooks
| Tool | What it does | Required scope | Kind |
|---|---|---|---|
list_webhooks | List all webhook configurations | webhooks:read | read |
get_webhook | Get a single webhook configuration by UUID | webhooks:read | read |
create_webhook | Register a new webhook URL to receive event notifications | webhooks:write | write |
update_webhook | Partially update a webhook configuration | webhooks:write | write |
delete_webhook | Remove a webhook subscription — deliveries stop immediately | webhooks:write | destructive |
Menu
| Tool | What it does | Required scope | Kind |
|---|---|---|---|
get_menu | Menu catalog: categories, products, prices, availability, images | menu:read | read |
list_categories | List menu categories (id, name, position, type, visibility) | menu:read | read |
get_category | Get one category by UUID | menu:read | read |
list_products | Paginated product list, optionally filtered by category | menu:read | read |
get_product | Get one product by UUID | menu:read | read |
list_product_variants | List a product's variants (name, price) | menu:read | read |
list_kitchens | List the company's kitchens | menu:read | read |
list_modifier_categories | List modifier categories with their modifiers | menu:read | read |
update_product | Update a product's name or description | menu:write | write |
create_product | Create a product with 1-30 variants (JSON only, no image) | menu:write | write |
create_product_variant | Create a variant on an existing product | menu:write | write |
update_product_variant | Partially update a product variant | menu:write | write |
sync_product_modifier_categories | Replace a product's modifier-category associations | menu:write | write |
create_modifier | Create a modifier in a modifier category | menu:write | write |
update_modifier | Partially update a modifier (e.g. its price) | menu:write | write |
update_product_position | Move a product to a new position within its category | menu:write | write |
update_category | Move a category to a new position and/or change its visibility | menu:write | write |
Logistics
| Tool | What it does | Required scope | Kind |
|---|---|---|---|
assign_rider | Assign or update the delivery rider for an order | logistics:write | write |
unassign_rider | Remove the assigned delivery rider from an order | logistics:write | destructive |
update_delivery_status | Update the delivery status of an order | logistics:write | write |
report_rider_position | Report the rider's current GPS position | logistics:write | write |
Company & users
| Tool | What it does | Required scope | Kind |
|---|---|---|---|
get_company | Company profile: identity, location, business hours, open-now flag | companies:read | read |
list_payment_methods | Active payment methods of the company | payment-methods:read | read |
list_users | Paginated company users, filterable by role and account status | users:read | read |
get_clients | List clients with filters (name, phone, status, source, points) | clients:read | read |
get_client | Get a single client by UUID: profile, points, order stats | clients:read | read |
create_client | Create a new client | clients:write | write |
update_client | Partially update a client's profile | clients:write | write |
Addresses
| Tool | What it does | Required scope | Kind |
|---|---|---|---|
list_addresses | List a client's delivery addresses | addresses:read | read |
create_address | Create a delivery address for a client | addresses:write | write |
update_address | Partially update a delivery address | addresses:write | write |
delete_address | Delete a delivery address | addresses:write | destructive |
Delivery
| Tool | What it does | Required scope | Kind |
|---|---|---|---|
get_delivery_pricing | Get the company's delivery pricing configuration | orders:read | read |
get_delivery_quote | Get a delivery price quote for an address | orders:read | read |
Cash registers
| Tool | What it does | Required scope | Kind |
|---|---|---|---|
list_cashiers | List the company's cash registers (id, name, default, open or closed); use the id to filter balances | cashiers:read | read |
list_cashier_balances | Cash register openings and closings: expected amount, counted amount, surplus/shortage and breakdown by payment method; filter by status, cash register and date range | cashiers:read | read |
get_cashier_balance | Get a single cash register balance by UUID | cashiers:read | read |
Dashboard
| Tool | What it does | Required scope | Kind |
|---|---|---|---|
get_menu_visits_today | Digital menu visits recorded today | reports:read | read |
get_menu_performance | Digital menu visits, confirmed carts and created orders over a date range, compared with the previous period | reports:read | read |
get_menu_conversion | The same metrics as percentages of menu visits | reports:read | read |
Other
| Tool | What it does | Required scope | Kind |
|---|---|---|---|
get_store_status | Whether the store is open on each food-delivery app | stores:read | read |
list_conections | List connections for the authenticated connector | conections:read | read |
update_conection_status | Accept or reject a pending connection | conections:write | write |
Write tools: how they behave
Arguments are the REST endpoint's path parameters and body fields, flattened into one argument list with the same names as the API (e.g. create_order takes service_type, client_id, table_id, ... — the same fields as POST /v1/orders's body; add_order_combos takes id, the order UUID from the path, plus combos, the body).
Local validation runs before any HTTP call: enums, UUID format, numeric bounds and required fields are checked in the MCP server itself, the same way the read tools already validate a page size or a UUID. A malformed call never reaches OlaClick.
create_order and idempotency_key: the REST endpoint requires an Idempotency-Key header. The tool exposes it as an optional idempotency_key argument; when omitted, the server generates one for you. Reuse the same idempotency_key when retrying a failed call — the API replays the original result instead of creating a second order.
MCP annotations: every tool advertises readOnlyHint, destructiveHint and idempotentHint per its kind (see the tables above). MCP clients that honor these hints — Claude Desktop, Cursor, and others — may ask you to confirm before running a destructive tool.
Errors: a failed call returns isError: true with the API's RFC 7807 problem details (type, detail, and a per-field errors[] when applicable) as the tool result, not a thrown exception, so the assistant can read the reason and correct the call (e.g. a missing required field, or a 422 coupon_not_applicable).
Scopes are enforced by the Public API, not by the MCP server: a write tool needs its matching *:write scope on the connecting key (e.g. orders:write for create_order), the same way a read tool needs its *:read scope.
Permissions (scopes)
Whether you authorize a connector via OAuth or generate an API key, access is broken into the same scopes. Grant only what the assistant needs.
| Scope | Unlocks |
|---|---|
menu:read | Read menu categories and products |
menu:write | Create and update products |
orders:read | Read orders |
orders:write | Create orders, update order status, items, payments and discounts, and cancel orders |
promotions:read | Read active promotions and coupons |
promotions:write | Create, update, and delete promotions (coupons) |
clients:read | Read client list with filters and pagination |
clients:write | Create and update clients |
addresses:read | Read client delivery addresses |
addresses:write | Create, update, and delete client delivery addresses |
reports:read | Read reports |
webhooks:read | List and view webhook configurations |
webhooks:write | Create, update, and delete webhooks |
companies:read | Read company information |
payment-methods:read | Read the company payment methods |
stores:read | Read food-app store open/closed status |
users:read | Read the company user list with role filter and pagination |
fiscal-notes:write | Create and update fiscal note invoices |
logistics:write | Assign riders and update delivery status |
cashiers:read | Read cash registers and cash register openings and closings |
Quick Start
Prerequisites
- An OlaClick panel account (Admin or Manager) for OAuth, or an OlaClick API Key (generated from the restaurant's panel under Integrations > API Keys) for stdio/local clients
- An MCP-compatible client (Claude Desktop, Claude Code, Cursor, VS Code with Copilot, etc.)
Configuration
The OlaClick MCP server uses HTTP (SSE) transport. Clients connect to the remote endpoint — no local installation needed.
Client Setup
Claude.ai / Claude Desktop (OAuth)
- Go to Settings → Connectors → Add custom connector.
- Paste the server URL:
https://public-api.olaclick.app/mcp. - Click Connect.
- Sign in to the OlaClick panel.
- Review the requested permissions.
- Click Authorize.
- You're back in Claude, connected.
Tokens are short-lived and refreshed automatically — you won't be asked to sign in again unless access is revoked. You can revoke the connector at any time from the OlaClick panel.
Claude Code (OAuth)
claude mcp add --transport http olaclick https://public-api.olaclick.app/mcp
Then run /mcp inside Claude Code and follow the prompt to sign in.
ChatGPT (OAuth)
ChatGPT connects to remote MCP servers through Developer Mode (Pro, Plus, Business, Enterprise and Education plans, on the web).
- Go to Settings → Apps & Connectors → Advanced settings and enable Developer mode.
- Back in Apps & Connectors, click Create (or +) to add a connector.
- Paste the server URL:
https://public-api.olaclick.app/mcpand choose OAuth as the authentication. - Sign in to the OlaClick panel, review the requested permissions and click Authorize.
- Start a chat, enable the OlaClick connector in the message composer, and ask away.
Write tools (create order, create product, etc.) are annotated as writes and irreversible ones (cancel an order, delete a promotion or a webhook) as destructive, so ChatGPT can apply its own safeguards; whether it asks you to confirm depends on ChatGPT and your settings. Tokens are short-lived and refreshed automatically.
Cursor
Add to CursorOr add manually to your project's .cursor/mcp.json:
{
"mcpServers": {
"olaclick": {
"url": "https://public-api.olaclick.app/mcp",
"headers": {
"Authorization": "Bearer olk_live_YOUR_KEY_HERE"
}
}
}
}
Claude Desktop
Add the following to your Claude Desktop configuration file:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"olaclick": {
"url": "https://public-api.olaclick.app/mcp",
"headers": {
"Authorization": "Bearer olk_live_YOUR_KEY_HERE"
}
}
}
}
VS Code (Copilot / Kiro)
Add the following to .vscode/mcp.json or .kiro/settings/mcp.json:
{
"mcpServers": {
"olaclick": {
"url": "https://public-api.olaclick.app/mcp",
"headers": {
"Authorization": "Bearer olk_live_YOUR_KEY_HERE"
}
}
}
}
Remote HTTP (Hosted)
Connect to the OlaClick MCP server directly via HTTP:
{
"mcpServers": {
"olaclick": {
"url": "https://public-api.olaclick.app/mcp",
"headers": {
"Authorization": "Bearer olk_live_YOUR_KEY_HERE"
}
}
}
}
In HTTP mode, the API key is passed via the
Authorization: Bearerheader on each connection. No environment variables needed. This is the API-key path — if you authorize via OAuth instead (see above), tools no longer expose anapi_keyparameter, since the session is already authenticated.
Example Prompts
Once connected, try asking Claude:
- "Show me today's orders and their status"
- "Which products sold the most this week?"
- "Create a takeaway order for María with 2 cheeseburgers and a Coke, paid in cash"
- "Add a new product called 'Veggie Wrap' at $8.50 to the Sandwiches category"
- "List the products in the Drinks category with their prices"
- "Which promotions are active right now?"
Write actions (creating an order, creating a product) are annotated as writes and irreversible ones as destructive; Claude decides, based on those annotations and your settings, whether to ask you to confirm before running them.
Troubleshooting
- "Authorization failed" — make sure you signed in as an Admin or Manager user; other roles can't authorize a connector.
- "Couldn't reach the MCP server" — check the URL ends in
/mcp. - Tokens expire — Claude refreshes them automatically; if the connector was revoked, just reconnect.
Tool Reference
Every tool validates its arguments before calling the API: a wrong type, a malformed UUID or a page size out of range is rejected by the MCP server and never reaches OlaClick.
get_orders
Retrieve a paginated list of orders with optional filters.
Note: If no
start_dateis provided, defaults to today's orders.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
order_id | string | No | UUID or public ID (e.g. PE-1234567890) to get a single order |
status | string | No | PENDING, PREPARING, READY, DELIVERED, FINALIZED, CANCELLED |
service_types | string | No | DELIVERY, TAKEAWAY, ONSITE, TABLE (comma-separated) |
source | string | No | Filter by source (e.g. web, ifood, rappi, uber) |
payment_status | string | No | Filter by payment status (e.g. PAID,PENDING) |
payment_method_ids | string | No | Comma-separated payment method UUIDs |
owner_ids | string | No | Comma-separated owner/cashier UUIDs |
rider_ids | string | No | Comma-separated rider UUIDs |
delivered_by | string | No | Filter by who delivered (e.g. MERCHANT,IFOOD,PICKER) |
delivery_status | string | No | Filter by delivery status |
is_scheduled | string | No | Filter scheduled orders (true or false) |
client_id | string | No | Filter by client UUID |
public_id | string | No | Search by partial public order ID |
cancelation_reason | string | No | Filter by cancelation reason |
start_date | string | No | From date (YYYY-MM-DD) |
end_date | string | No | Until date (YYYY-MM-DD) |
start_time | string | No | From time (HH:mm:ss) |
end_time | string | No | Until time (HH:mm:ss) |
time_type | string | No | Date column to filter on (default: pending_at) |
timezone | string | No | Timezone for date filters (default: company timezone) |
page | number | No | Page number (default: 1) |
per_page | number | No | Items per page (1-100, default: 50) |
Example prompt:
"Show me today's pending delivery orders"
Response format:
{
"data": [
{
"id": "9c4f4203-9e2c-403d-88cc-7c0ce9e0f572",
"public_id": "PE-9799906639",
"status": "finalized",
"service_type": "onsite",
"source": "OUTBOUND",
"utm_source": "meta",
"utm_campaign": "combos-julio",
"client": {
"name": "John Doe"
},
"address": {
"city": "Lima",
"area": "Miraflores"
},
"total": 90,
"total_paid": 90,
"total_tips": 0,
"total_discounts": 0,
"delivery_price": 0,
"service_fee_price": 0,
"combos_price": 90,
"created_at": "2026-06-23T18:23:42+00:00",
"updated_at": "2026-06-23T18:56:00+00:00"
}
],
"pagination": {
"current_page": 1,
"per_page": 50,
"total": 12,
"has_more": false
}
}
get_clients
Retrieve a paginated list of clients with optional filters.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
filter_name | string | No | Partial match on client name (accent-insensitive) |
filter_phone_number | string | No | Matches phone number prefix |
filter_country_calling_code | string | No | Country calling code (used with phone_number) |
filter_type | string | No | Frequency classification (comma-separated): ELITE_BUYER, TOP_BUYER, FREQUENT_BUYER, REPEAT_BUYER, BUYER, NO_BUYER |
filter_status | string | No | Recency classification (comma-separated): ACTIVE, INACTIVE, SLEEPING, AT_RISK |
filter_source | string | No | chatbot, ecommerce, panel (comma-separated) |
filter_available_points | number | No | Clients with available_points greater than this value |
filter_used_points | number | No | Clients with used_points greater than this value |
sort_by | string | No | name, phone_number, available_points, used_points, source, total_orders, address |
direction | string | No | asc or desc |
include_addresses | boolean | No | Include client addresses in response |
simple_paginate | boolean | No | Use simple pagination (faster, no total count) |
page | number | No | Page number (default: 1) |
per_page | number | No | Items per page (1-100, default: 25) |
Every client carries two independent classifications, both computed by OlaClick:
type— how often they buy, by lifetime order count:ELITE_BUYER(more than 7 orders),TOP_BUYER(5–7),FREQUENT_BUYER(3–4),REPEAT_BUYER(2),BUYER(1),NO_BUYER(0).status— how recently they bought, by days since their last order:ACTIVE(under 16 days),INACTIVE(16–30),SLEEPING(31–91),AT_RISK(over 91 days, or never ordered).
Combine them to build audiences: filter_status=SLEEPING finds customers about
to churn, while filter_status=AT_RISK plus a type other than NO_BUYER finds
lapsed customers worth winning back.
Example prompt:
"List my top 10 clients sorted by total orders"
Response format:
{
"data": [
{
"id": "9c8e720f-31b1-485a-85fa-0aaf552faaa9",
"name": "John Doe",
"email": "john@example.com",
"phone_number": "3001234567",
"country_calling_code": "57",
"available_points": 150,
"used_points": 0,
"status": "AT_RISK",
"type": "BUYER",
"source": "ecommerce",
"total_orders": 8,
"created_at": "2024-07-19T02:28:48+00:00"
}
],
"pagination": {
"current_page": 1,
"per_page": 25,
"total": 340,
"has_more": true
}
}
create_client
Create a new client for the authenticated company: name, phone number (with country calling code), and an optional email.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Client name, 1-150 characters |
phone_number | string | Yes | National phone number, without the country code. Digits only |
country_calling_code | string | Yes | Country calling code, without the leading "+", e.g. "51" for Peru |
email | string | No | Email address |
Example prompt:
"Create a client named María López, phone 987654321, country code 51"
A duplicate phone number fails with 422 client_already_exists.
update_client
Partially update a client by UUID: name, phone number, country calling code, or email. Only the fields you send are changed.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Client UUID |
name, phone_number, country_calling_code, email | — | No* | *At least one required |
Example prompt:
"Update client X's email to maria@example.com"
list_addresses
List the delivery addresses of one client: street address, coordinates, delivery district (area), and which one is the default. Paginated.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
client_id | string (UUID) | Yes | Client UUID to list addresses for |
page | integer | No | Page number (default: 1) |
per_page | integer | No | Items per page, 1-100 |
Example prompt:
"List the saved addresses for client 9c8e720f-31b1-485a-85fa-0aaf552faaa9"
create_address
Create a new delivery address for a client: street address, optional complement, reference,
coordinates, and delivery district. Returns the created address, whose id can be used as
address_id when creating a DELIVERY order.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
client_id | string (UUID) | Yes | Client this address belongs to |
address | string | Yes | Street address, 1-191 characters |
complement | string | No | Apartment, suite, floor, etc. Max 100 characters |
reference | string | No | A landmark or note to help find the address. Max 100 characters |
latitude, longitude | number | No* | *Both or neither, decimal degrees |
area_id | string (UUID) | No | Delivery district id, for merchants priced by district |
default | boolean | No | Whether this becomes the client's default delivery address |
Example prompt:
"Save a new address for client X at Av. Larco 345, Miraflores, lat -12.1211, long -77.0295, and make it the default"
update_address
Partially update a client delivery address by UUID. Only the fields you send are changed; the owning client cannot be changed. Returns the updated address.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Address UUID |
address, complement, reference, latitude, longitude, area_id, default | — | No | Same shape as create_address; latitude/longitude must still be sent together |
Example prompt:
"Update address X to set latitude -12.1211 and longitude -77.0295"
delete_address
Delete a client delivery address by UUID. This cannot be undone.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Address UUID |
get_delivery_pricing
Get the authenticated company's delivery pricing configuration: whether delivery is active,
the pricing mode, and the mode-specific parameters. Call this first, before
get_delivery_quote, to learn which pricing mode applies and which inputs the quote call
needs — FIXED and BY_DISTRICT already carry the delivery price in this response, no quote
call needed.
No parameters. Mirrors GET /v1/delivery/pricing.
Example prompt:
"How does my restaurant charge for delivery?"
get_delivery_quote
Resolve the delivery price for one address. Send latitude/longitude for the BY_AREA,
BY_DRIVE_DISTANCE, or BY_RANGE pricing modes, or district_id for BY_DISTRICT — call
get_delivery_pricing first to know which. A price of 0 with a null area means the address
is outside coverage but the merchant still accepts it.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
latitude, longitude | number | No* | *Both or neither, decimal degrees |
district_id | string (UUID) | No | District id from get_delivery_pricing's districts[] |
Example prompt:
"How much would delivery cost to latitude -34.5955, longitude -58.3930?"
get_menu
Retrieve the menu catalog: what you sell, at what price, and whether it's available. This is the source for building product catalogs and ad feeds (Meta / Google Shopping).
Note: the menu is not paginated — a large catalog arrives in a single response. Pass
category_slugto keep the response to one category. The tool still fetches the full menu and filters it for you.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
category_slug | string | No | Return only the category whose slug matches (e.g. combos). Use the slug value this tool returns per category, not the category name or id. An unknown slug returns an error listing the available slugs. |
available_only | boolean | No | Drop products that are currently unavailable |
Example prompt:
"List my combos with their prices and tell me which ones are out of stock"
Response format:
{
"data": {
"categories": [
{
"id": "026de0fc-85d9-47cd-9c34-627996b6c01c",
"slug": "combos",
"name": "Combos",
"position": 0,
"products": [
{
"id": "9c4f4203-9e2c-403d-88cc-7c0ce9e0f572",
"slug": "combo-classic-smash",
"name": "Combo Classic Smash",
"description": "Smash burger with fries",
"variants": [
{
"id": "6b2f1a04-1c7e-4a2b-9f11-2d8e0b3c4d55",
"name": "Default",
"price": 26,
"currency": "PEN"
}
],
"available": true,
"image_url": "https://assets.olaclick.app/combo-classic-smash.webp"
}
]
}
]
}
}
Prices are in major units (26 means 26.00) with an ISO 4217 currency.
image_url is the primary image only. Products with no variants are omitted,
since they have no price.
get_products_sold
Retrieve statistics about the most sold products.
Note: If no
start_dateis provided, defaults to the last 7 days.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
include | string | No | Grouping: products, products_modifiers, freehand |
show_products | number | No | Limit to top N products |
category_ids | string | No | Comma-separated category IDs |
combo_type | string | No | Freehand combo type filter (only when include=freehand) |
status | string | No | Order statuses (e.g. finalized,delivered) |
sources | string | No | Order sources (e.g. inbound,outbound) |
service_types | string | No | Service types (e.g. delivery,onsite) |
start_date | string | No | Start date (YYYY-MM-DD) |
end_date | string | No | End date (YYYY-MM-DD) |
timezone | string | No | Timezone (default: company timezone) |
page | number | No | Page number (default: 1) |
per_page | number | No | Items per page (1-100, default: 25) |
Example prompt:
"What are my top 5 best-selling products this week?"
Response format:
{
"data": [
{
"product_name": "Combo Classic Smash",
"product_quantity": 41,
"average_price": 39,
"total_sales": 1599,
"modifiers": [],
"product_id": "9c4f4203-9e2c-403d-88cc-7c0ce9e0f572",
"variant_id": "9c4f4203-a0ec-45bc-9810-3a8ada0838dd"
}
],
"pagination": {
"current_page": 1,
"per_page": 25,
"total": 45,
"has_more": true
}
}
update_product
Update a product's name and/or description.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
product_id | string | Yes | UUID of the product to update |
name | string | No** | New product name (max 191 chars) |
description | string | No** | New product description |
**At least one of name or description must be provided.
Example prompt:
"Rename product 9c4f4203-9e2c-403d-88cc-7c0ce9e0f572 to 'Double Smash Burger'"
Response format:
{
"data": {
"id": "9c4f4203-9e2c-403d-88cc-7c0ce9e0f572",
"name": "Double Smash Burger",
"description": "Two smashed beef patties with cheese"
}
}
list_categories
List the company's menu categories: id, name, position, type, visible. No
products, no slug. Use it to browse the catalog structure before listing products.
No parameters. Mirrors GET /v1/menu/categories.
Example prompt:
"Which categories does my menu have, and which ones are hidden?"
get_category
Get a single menu category by UUID.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Category UUID |
Mirrors GET /v1/menu/categories/{id}. A non-UUID id is rejected locally.
list_products
Paginated product list: id, name, description, position, visible,
category_id per product. No variants, no slug.
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number, 1 or greater (default: 1) |
per_page | integer | No | Items per page, 1-100 (default: 20) |
category_id | string (UUID) | No | Only products in this category |
Mirrors GET /v1/menu/products. A per_page outside 1-100 is rejected locally.
Example prompt:
"List the products in my Combos category"
get_product
Get a single product by UUID: id, name, description, position, visible,
category_id, plus its variants.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Product UUID |
Mirrors GET /v1/menu/products/{id}.
list_product_variants
List the variants of one product: id, name, price, original_price, currency,
sku, stock, stock_threshold, position per variant. Use it to see the purchasable
options of a product returned by get_product or list_products.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Product UUID |
Mirrors GET /v1/menu/products/{id}/variants.
Example prompt:
"What sizes and prices does product 9c4f4203-9e2c-403d-88cc-7c0ce9e0f572 have?"
list_kitchens
List the kitchens configured for the company: id, name, default per kitchen. Use it
to find valid kitchen ids.
No parameters. Mirrors GET /v1/menu/kitchens.
list_tables
List the company's zones (rooms) and their tables: each zone has id, name and qrs
(the tables/QR points in that zone, each with id, name, nullable description and
position). Use it to find valid table_id values when creating a TABLE order.
No parameters. Mirrors GET /v1/tables.
get_company
Get the profile of the company behind the credential: name, description, logo,
public URL, language, currency, location, weekly business hours, and currently_open
computed in the company timezone. Requires the companies:read scope.
No parameters. Mirrors GET /v1/company.
Example prompt:
"Is my restaurant open right now, and what are today's hours?"
list_payment_methods
List the active payment methods of the company: only those enabled for at least one order
service type (ONSITE, TABLE, DELIVERY, TAKEAWAY) are returned. Requires the
payment-methods:read scope.
No parameters. Mirrors GET /v1/company/payment-methods.
list_users
Paginated list of the company's users, with role and account status. Requires the
users:read scope.
| Parameter | Type | Required | Description |
|---|---|---|---|
role | string | No | Comma-separated roles: admin, manager, waiter, rider, cook, sales, cashier |
active | boolean | No | true only active users, false only deactivated users; omit for both |
page | integer | No | Page number, 1 or greater (default: 1) |
per_page | integer | No | Items per page, 1-100 (default: 20) |
Mirrors GET /v1/users, where role and active are sent as filter[role] and filter[active].
Example prompt:
"Which riders do I have active right now?"
create_order
Create an order and return it. Starts as INITIATED (a draft) unless you send status: PENDING. Add items with add_order_combos, then confirm the draft with update_order_status.
| Parameter | Type | Required | Description |
|---|---|---|---|
service_type | string | Yes | ONSITE, TABLE, DELIVERY, or TAKEAWAY |
client_id | string (UUID) | No | An existing client of your company |
table_id | string (UUID) | No | Only for TABLE orders; find one with list_tables |
address_id | string (UUID) | No | Only for DELIVERY orders |
delivery_price | number | No | Only for DELIVERY orders |
status | string | No | Send PENDING to skip the INITIATED draft |
comment, order_title, packaging_price, scheduled_delivery_date | — | No | Optional order metadata |
idempotency_key | string | No | Reused on retry to avoid a duplicate order; generated when omitted |
Example prompt:
"Create a takeaway order for client 9c8e720f-31b1-485a-85fa-0aaf552faaa9"
add_order_combos
Add one or more items to an order and return it with totals recalculated.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Order UUID |
combos | array | Yes | Items to add — each needs variant_id and quantity; modifiers is optional (modifier_id, quantity per modifier) |
Example prompt:
"Add 2 Classic Smash combos to order 9c4f4203-9e2c-403d-88cc-7c0ce9e0f572"
add_order_payment
Register a payment against an order and return it with payment totals recalculated.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Order UUID |
payment_method_id | string (UUID) | Yes | From list_payment_methods |
bill_amount | number | Yes | Amount charged |
received_amount | number | No | Amount actually received (cash tendered) |
tip_amount | number | No | Tip included in this payment |
Example prompt:
"Register a cash payment of 45.50 on order X"
apply_order_coupon
Redeem a coupon code on an order and return it with totals recalculated. The order must have a client attached.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Order UUID |
code | string | Yes | Coupon code, e.g. VERANO20 |
Example prompt:
"Apply coupon VERANO20 to order X"
update_order_status
Change the status of an order and return it. Orders only move forward.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Order UUID |
status | string | Yes | New status, e.g. PENDING, PREPARING, READY, DELIVERED, FINALIZED |
Example prompt:
"Move order X to PREPARING"
cancel_order
Cancel an order created through the API and return it. It must have no active payments — remove them first with remove_order_payment.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Order UUID |
reason | string | Yes | Cancelation reason code |
detail | string | No | Free-text detail |
Example prompt:
"Cancel order X, the customer changed their mind"
create_promotion
Create a promotion (coupon): a code, a discount, and eligibility rules.
| Parameter | Type | Required | Description |
|---|---|---|---|
name, coupon_code | string | Yes | Display name and the redeemable code |
discount_type, discount_value | string, number | Yes | e.g. PERCENTAGE + 20, or a fixed amount |
minimum_order_amount | number | Yes | Order total floor for the coupon to apply |
valid_from, valid_until | string (date) | Yes | Validity window |
usage_limit | number | Yes | Total redemptions allowed |
published | boolean | Yes | Whether it's live on the digital menu |
promotion_type, products, service_types, audience, usage_limit_per_customer, schedule, terms | — | No | Optional restrictions and metadata |
Example prompt:
"Create a 20% coupon VERANO20 valid until December for delivery only"
update_promotion
Partially update a promotion. Same fields as create_promotion, all optional — a field can be set but not cleared back to unset.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Promotion UUID |
any create_promotion field | — | No | Only the fields you send are changed |
Example prompt:
"Extend promotion X's valid_until to January 31"
delete_promotion
Delete a promotion by UUID. Cannot be undone.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Promotion UUID |
Example prompt:
"Delete the VERANO20 promotion"
create_webhook
Register a new webhook URL to receive event notifications.
| Parameter | Type | Required | Description |
|---|---|---|---|
webhook_url | string (URL) | Yes | HTTPS endpoint that receives events |
merchant_id | string | Yes | Your own identifier for this merchant |
webhook_headers | object | No | Custom headers sent with every delivery |
max_retry | integer | No | Retries on failure, 0-10 (default 3) |
ack_http_codes | array | No | HTTP codes considered successful (default [200, 201, 202]) |
event_types | array | No | Event types to subscribe to; omit for all events |
Example prompt:
"Create a webhook to https://example.com/hooks for merchant store-42"
update_webhook
Partially update a webhook configuration. Only the fields you send are changed — send is_active: false to pause a webhook without deleting it.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Webhook UUID |
webhook_url, webhook_headers, is_active, max_retry, ack_http_codes, event_types | — | No | Same shape as create_webhook |
Example prompt:
"Pause my webhook X"
delete_webhook
Remove a webhook subscription by UUID. Deliveries stop immediately.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Webhook UUID |
create_product
Create a product with 1-30 variants via JSON only (no image upload from the MCP). Prices are decimals, not minor units.
| Parameter | Type | Required | Description |
|---|---|---|---|
category_id, kitchen_id, name | string | Yes | From list_categories / list_kitchens |
variants | array | Yes | 1-30 variants; each needs name, price, original_price, sku |
description, visible, modifier_category_ids | — | No | Optional fields |
Example prompt:
"Create a product 'Iced Latte' in the Drinks category, one variant at 12.00"
create_product_variant
Create a variant on an existing product.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Product UUID |
name, price, original_price, sku | — | Yes | price must not exceed original_price |
cost, packaging_price, stock, stock_threshold | — | No | Optional fields |
Example prompt:
"Add a Large variant at 15.50 to product X"
update_product_variant
Partially update a product variant. All fields are optional but at least one must be provided.
| Parameter | Type | Required | Description |
|---|---|---|---|
id, variantId | string (UUID) | Yes | Product and variant UUIDs |
name, price, original_price, cost, packaging_price, sku, stock, stock_threshold | — | No* | *At least one required |
sync_product_modifier_categories
Replace a product's modifier-category associations, in the given order.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Product UUID |
modifier_category_ids | array (UUID) | Yes | Distinct UUIDs, from list_modifier_categories; an empty array detaches all |
create_modifier
Create a modifier inside a modifier category. price is what customers pay; it defaults to original_price and must not exceed it.
| Parameter | Type | Required | Description |
|---|---|---|---|
name, original_price, modifier_category_id, max_limit, visible | — | Yes | From list_modifier_categories for modifier_category_id |
price, sku | — | No | price is the charged price; set it below original_price for a discount |
Example prompt:
"Add a modifier 'Extra cheese' at 1.50 to the Toppings modifier category"
update_modifier
Partially update a modifier by its UUID. All fields are optional but at least one must be provided. The main use case is updating a modifier's price.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Modifier UUID |
name, price, original_price, sku, max_limit, visible | — | No* | *At least one required; price is what customers pay and must not exceed original_price. Sending only original_price also moves price when there is no discount |
Example prompt:
"Update the Extra cheese modifier to cost 1.80"
update_product_position
Move a product to a new position within its category. The product moves to the given position and the other products in that category shift by one to make room.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Product UUID |
position | integer | Yes | New 0-based position; greater than the last existing position fails |
update_category
Partially update a menu category: move it to a new position among sibling categories, and/or change its visibility. At least one field must be provided.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Category UUID |
position | integer | No* | New 0-based position; greater than the last existing position, or moving a favorites category, fails |
visible | boolean | No* | false hides the whole category, including its products, from the menu |
*At least one of position/visible required.
assign_rider
Assign or update the delivery rider for an order.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Order UUID |
name | string | Yes | Rider name |
provider | string | No | api (default, external rider) or olaclick |
user_id | string (UUID) | No* | *Required when provider: olaclick; must be an active rider-role user |
phone_number | string | No | Rider phone number |
Example prompt:
"Assign rider Marco to order X, phone 555-0100"
update_delivery_status
Update the delivery status of an order.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string (UUID) | Yes | Order UUID |
delivery_status | string | Yes | e.g. ON_THE_WAY_TO_PICK_UP, DELIVERING, DELIVERED |
Example prompt:
"Mark order X as out for delivery"
Authentication
The MCP server supports two authentication methods in HTTP mode:
-
OAuth — Claude.ai, Claude Desktop, Claude Code, and other OAuth-capable clients authenticate via the standard OAuth 2.1 flow (see Two ways to authenticate). No API key involved.
-
API key — clients that don't support OAuth pass an API key via the HTTP Authorization header:
Authorization: Bearer olk_live_YOUR_KEY_HEREThe key is passed on the initial HTTP/SSE connection. All tool calls within that session inherit it automatically — no need to pass it per-call.
Example Conversations
Here are some example prompts you can use once the MCP server is connected:
| Prompt | Tool Used |
|---|---|
| "How many orders did I get today?" | get_orders |
| "Show me all cancelled orders from last week" | get_orders |
| "List delivery orders that are still pending" | get_orders |
| "Which orders came from my Meta campaigns this month?" | get_orders |
| "Who are my most frequent customers?" | get_clients |
| "Find the client with phone number 300..." | get_clients |
| "Which customers are about to churn?" | get_clients |
| "List my menu with prices" | get_menu |
| "Which products are out of stock right now?" | get_menu |
| "What's my best-selling product this month?" | get_products_sold |
| "Show top 10 products for delivery orders" | get_products_sold |
| "Update the description of product X" | update_product |
| "Which categories does my menu have, and which are hidden?" | list_categories |
| "Show me the products in my Combos category" | list_categories, then list_products |
| "What are the details of product X?" | get_product |
| "What sizes and prices does product X come in?" | list_product_variants |
| "Which kitchens do I have set up?" | list_kitchens |
| "Is my restaurant open right now? What are today's hours?" | get_company |
| "Which payment methods do I accept for delivery?" | list_payment_methods |
| "Which riders are active right now?" | list_users |
| "List my managers and cashiers" | list_users |
| "Create a takeaway order for client X with 2 burgers and register a cash payment" | create_order, add_order_combos, add_order_payment |
| "Create a 20% coupon VERANO20 valid until December for delivery only" | create_promotion |
| "Pause my webhook" | update_webhook |
| "Add a Large variant at 15.50 to product X" | create_product_variant |
| "Add a modifier 'Extra cheese' at 1.50 to the Toppings modifier category" | create_modifier |
| "Update the Extra cheese modifier to cost 1.80" | update_modifier |
| "Assign rider Y to order Z" | assign_rider |
| "Mark order Z as out for delivery" | update_delivery_status |
| "Cancel order Z, the customer changed their mind" | cancel_order |
Security
- API keys are never logged or stored by the MCP server
- All communication uses HTTPS
- Each user provides their own key via the Authorization header
- Scopes are enforced by the Public API, not by the MCP server: calling a tool
with a key that lacks its scope (e.g.
menu:readforget_menu) fails upstream with403 insufficient_scope - Write tools change real data — a created order, an updated promotion, or a deleted webhook is real; there is no dry-run mode at the MCP layer
- Use a key scoped to only the write scopes an assistant actually needs (e.g.
don't hand out
orders:writeto an assistant that only reads the menu) - Destructive tools (backed by
DELETE) carry MCP'sdestructiveHintannotation; clients like Claude Desktop or Cursor may ask you to confirm before running one - Treat any API key with a
*:writescope as a production credential — store and rotate it the same way you would a database password
Next Steps
- Getting Started — Get your API key and make your first call
- API Reference — Full endpoint documentation
- Webhooks — Real-time event notifications