Vol. 1, No. 1Est. 2026CDMX / NYC / SF

EN|

Developer Documentation · v1.1

Agent Protocol API Reference

A REST API for AI agents to discover restaurants, browse menus, and place orders. ACP-compliant checkout with Stripe Shared Payment Tokens.

§ 01

Quickstart

Go from zero to a confirmed restaurant order in five requests. Pick a language tab in any code block. Your choice syncs to every other block on the page.

1 · Register an API key

Self-serve, instant. Save the key field. It is shown only once.

curl -X POST https://api.menami.mx/api/v1/agent/keys/register \
  -H "Content-Type: application/json" \
  -d '{
    "platform_name": "AcmeAgent",
    "contact_email": "dev@acme.ai",
    "website_url": "https://acme.ai",
    "description": "Voice agent for restaurant ordering"
  }'

2 · Find a restaurant

Discovery endpoints are public. No auth needed.

curl "https://api.menami.mx/api/v1/agent/restaurants?city=mexico&cuisine=mexican&limit=5"

3 · Fetch the menu

Menu responses include full modifier groups (sizes, sides, add-ons) and dietary tags.

curl "https://api.menami.mx/api/v1/agent/restaurants/tacos-el-padrino/menu"

4 · Create a checkout session

POSTs require an Idempotency-Key header. The server validates items, resolves modifiers, calculates tax plus delivery, and returns an ACP-shaped session.

curl -X POST https://api.menami.mx/api/v1/agent/checkout_sessions \
  -H "Content-Type: application/json" \
  -H "X-Agent-Key: $MENAMI_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "restaurant_slug": "tacos-el-padrino",
    "currency": "mxn",
    "line_items": [
      { "id": "550e8400-e29b-41d4-a716-446655440001", "quantity": 3 }
    ],
    "customer": {
      "name": "Carlos Martinez",
      "phone": "+525598765432"
    }
  }'

5 · Complete with a Shared Payment Token

Pass a Stripe SPT (or any ACP-compliant token). The server creates the PaymentIntent on the restaurant's connected account and dispatches the order.

curl -X POST https://api.menami.mx/api/v1/agent/checkout_sessions/cs_abc123/complete \
  -H "Content-Type: application/json" \
  -H "X-Agent-Key: $MENAMI_KEY" \
  -d '{
    "payment_data": {
      "handler_id": "card_tokenized",
      "instrument": {
        "type": "card",
        "credential": { "type": "spt", "token": "spt_abc123..." }
      }
    }
  }'

NOTE · MCP USERS

Already speak MCP? Skip the REST layer entirely. Install @menami/mcp-server and your agent gets recommendations, booking, ordering, and feedback as native MCP tools. See SDKs and integrations.

§ 02

Overview

The Menami Agent Protocol is a REST API that enables AI agents (personal assistants, custom GPTs, autonomous ordering bots, search indexers) to discover restaurants, browse menus with full modifier details, complete orders programmatically, and track delivery.

The checkout flow is ACP-compliant (Agentic Commerce Protocol by Stripe and OpenAI). Any ACP-compatible agent can complete purchases using Stripe Shared Payment Tokens without additional integration work.

SPEC · BASE

Base URL: https://api.menami.mx/api/v1/agent

Format: JSON in, JSON out. Set Content-Type: application/json on POST bodies.

Pagination: List endpoints accept page (default 1) and limit (default 20, max 100).

OpenAPI: Full spec at api.menami.mx/openapi.yaml. Generate SDKs in any language.

§ 03

Authentication

Discovery endpoints (listing restaurants, viewing menus, sitemap) require no authentication. Checkout, delivery quotes, and order status require an API key.

API key

Pass your API key via the X-Agent-Key header. For ACP compatibility, Authorization: Bearer <key> is also accepted. Both header names route to the same auth check.

curl https://api.menami.mx/api/v1/agent/orders/$ORDER_ID/status \
  -H "X-Agent-Key: ak_live_7f3a9b2c..."

# ACP-style equivalent:
curl https://api.menami.mx/api/v1/agent/orders/$ORDER_ID/status \
  -H "Authorization: Bearer ak_live_7f3a9b2c..."

Rate limits

Default rate limit is 60 requests per minute per API key. Rate-limited responses return HTTP 429 with a Retry-After header (seconds). Self-serve key registration is additionally rate-limited to 5 registrations per IP per hour. Need higher limits as a partner? agents@menami.mx.

Idempotency

All POST endpoints require an Idempotency-Key header (UUID v4 recommended). Same key plus identical body returns the cached response. Same key plus different body returns 422 idempotency_conflict. Keys are retained for 24 hours.

Request correlation

Every response includes an X-Request-Id header. If you supply your own value on the request, we echo it back; otherwise we mint a req_* UUID. Include this ID in any support email and we can trace the request end-to-end in seconds.

§ 04

Test mode

Build and integrate without ever placing a real order. Pass mode: "test" when registering a key and you get back an ak_test_* key. Test keys behave identically to live keys at the protocol level (same endpoints, same response shapes, same idempotency), but the checkout completion step does not charge a card or notify the restaurant.

Register a test key
curl -X POST https://api.menami.mx/api/v1/agent/keys/register \
  -H "Content-Type: application/json" \
  -d '{
    "platform_name": "AcmeAgent",
    "contact_email": "dev@acme.ai",
    "mode": "test"
  }'

Differences in test mode:

  • POST /checkout_sessions/:id/complete skips Stripe entirely and returns a synthetic pi_test_* payment intent ID.
  • The order is still created in the database (with channel="agent_test" and test_mode=true on the response) so you can exercise the full lifecycle including webhooks.
  • Order status webhooks fire for both live and test keys. Emit fake status transitions from the admin console to drive your integration.
  • Discovery endpoints behave identically; you can browse the real restaurant catalog.

List endpoints support two pagination modes. Pick the one that fits your access pattern:

Page-based (default)

Pass page and limit. Convenient for UI pagers (we return total). Not stable across writes: if the catalog changes mid-iteration you can miss or duplicate rows.

Cursor-based (recommended for crawlers)

Pass starting_after=<slug> from the previous response's next_cursor field. Results are ordered by slug, so iteration is stable even while restaurants are being added or modified. Keep going until next_cursor is null.

Cursor walk
# First page — no cursor
curl "https://api.menami.mx/api/v1/agent/restaurants?limit=100"
# Subsequent pages — pass the next_cursor from the previous response
curl "https://api.menami.mx/api/v1/agent/restaurants?starting_after=tacos-el-padrino&limit=100"

Combine with updated_since to crawl only the rows that changed since your last sweep. See Indexing and partners.

§ 06

Discovery endpoints

Browse and search the restaurant catalog. No authentication required.

GET/api/v1/agent/restaurantsNo auth

Search and filter restaurants. Returns active, ordering-enabled, Stripe-onboarded restaurants.

ParamTypeDescription
qstringFree-text search across name and cuisine.
citystringFilter by city (case-insensitive partial match).
cuisinestringFilter by cuisine type (case-insensitive partial match).
updated_sinceISO-8601Return only restaurants modified at or after this timestamp. Use for incremental indexing.
starting_afterstringCursor. Pass next_cursor from the previous response for stable iteration. Mutually informative with page.
pageintegerPage number (default: 1). Ignored when starting_after is set.
limitintegerResults per page (default: 20, max: 100).
curl "https://api.menami.mx/api/v1/agent/restaurants?city=mexico&cuisine=mexican&limit=5"
Response
{
  "total": 47,
  "page": 1,
  "limit": 20,
  "next_cursor": null,
  "has_more": true,
  "restaurants": [
    {
      "name": "Tacos El Padrino",
      "slug": "tacos-el-padrino",
      "cuisine": ["mexican"],
      "city": "Mexico City",
      "country": "MX",
      "currency": "MXN",
      "delivery": true,
      "pickup": true,
      "ordering_enabled": true,
      "min_order_amount": 15000,
      "estimated_prep_minutes": 25,
      "item_count": 34,
      "updated_at": "2026-05-01T12:00:00.000Z"
    }
  ]
}

All monetary amounts (e.g. min_order_amount) are in minor units: cents for USD, centavos for MXN.

GET/api/v1/agent/restaurants/:slugNo auth

Full restaurant details including address, operating hours, and a Schema.org JSON-LD Restaurant block in the schema_org field.

Response
{
  "name": "Tacos El Padrino",
  "slug": "tacos-el-padrino",
  "cuisine": ["mexican"],
  "address": {
    "street": "Av. Insurgentes Sur 1234",
    "city": "Mexico City",
    "state": "CDMX",
    "zip": "03100",
    "country": "MX"
  },
  "phone": "+525512345678",
  "email": "hola@tacoselpadrino.mx",
  "currency": "MXN",
  "timezone": "America/Mexico_City",
  "operating_hours": {
    "monday": [{ "open": "11:00", "close": "22:00" }],
    "friday": [{ "open": "11:00", "close": "23:00" }],
    "sunday": [{ "open": "10:00", "close": "21:00" }]
  },
  "delivery": true,
  "pickup": true,
  "ordering_enabled": true,
  "min_order_amount": 15000,
  "estimated_prep_minutes": 25,
  "website_url": "https://tacos-el-padrino.orderin.ai",
  "updated_at": "2026-05-10T08:30:00.000Z",
  "schema_org": {
    "@context": "https://schema.org",
    "@type": "Restaurant",
    "name": "Tacos El Padrino",
    "url": "https://tacos-el-padrino.orderin.ai",
    "servesCuisine": ["mexican"],
    "address": {
      "@type": "PostalAddress",
      "streetAddress": "Av. Insurgentes Sur 1234",
      "addressLocality": "Mexico City",
      "addressRegion": "CDMX",
      "postalCode": "03100",
      "addressCountry": "MX"
    },
    "telephone": "+525512345678",
    "hasMenu": "https://tacos-el-padrino.orderin.ai/menu"
  }
}
GET/api/v1/agent/restaurants/:slug/menuNo auth

Full menu with categories, items, dietary tags, allergens, and modifier groups (customization options).

curl "https://api.menami.mx/api/v1/agent/restaurants/tacos-el-padrino/menu"
Response (truncated)
{
  "restaurant_slug": "tacos-el-padrino",
  "currency": "MXN",
  "last_updated": "2026-05-12T17:42:00.000Z",
  "categories": [
    {
      "name": "Tacos",
      "slug": "tacos",
      "description": "Handmade corn tortillas",
      "items": [
        {
          "id": "550e8400-e29b-41d4-a716-446655440001",
          "name": "Taco al Pastor",
          "description": "Marinated pork with pineapple, cilantro, onion",
          "price": 4500,
          "currency": "MXN",
          "dietary_tags": ["gluten_free"],
          "allergens": [],
          "available": true,
          "image_url": "https://cdn.menami.mx/taco-pastor.jpg",
          "modifier_groups": [
            {
              "id": "group-uuid-1",
              "name": "Spice Level",
              "selection_type": "single_select",
              "required": true,
              "min_selections": 1,
              "max_selections": 1,
              "options": [
                { "id": "mod-1", "name": "Mild",   "price_adjustment": 0 },
                { "id": "mod-2", "name": "Medium", "price_adjustment": 0 },
                { "id": "mod-3", "name": "Hot",    "price_adjustment": 0 }
              ]
            }
          ]
        }
      ]
    }
  ]
}
GET/api/v1/agent/sitemap.jsonNo auth

Every active restaurant slug with its updated_at timestamp and canonical detail/menu URLs. Designed for search indexers to bootstrap or refresh their index. Cached for 5 minutes at the edge.

curl https://api.menami.mx/api/v1/agent/sitemap.json
Response
{
  "version": "1.0",
  "generated_at": "2026-05-26T08:00:00.000Z",
  "total": 8421,
  "restaurants": [
    {
      "slug": "tacos-el-padrino",
      "city": "Mexico City",
      "country": "MX",
      "updated_at": "2026-05-24T16:12:00.000Z",
      "detail_url": "/api/v1/agent/restaurants/tacos-el-padrino",
      "menu_url":   "/api/v1/agent/restaurants/tacos-el-padrino/menu"
    }
  ]
}
§ 07

Indexing & partners

Building a search engine, recommendation system, or AI agent that needs the full Menami catalog? You don't need an API key for read-only crawling, but you do need to play nice with our infrastructure.

Recommended crawl pattern

  1. Initial seed: Pull /sitemap.json once to get every active slug and its updated_at.
  2. Fetch detail and menu: For each slug, hit /restaurants/:slug and /restaurants/:slug/menu. The detail response includes a ready-to-use Schema.org JSON-LD Restaurant block.
  3. Incremental refresh: Store the max updated_at from your last batch. On the next crawl, hit /restaurants?updated_since=<timestamp>&limit=100. You'll only pay the bandwidth for what changed.
Incremental crawl
# Fetch only restaurants updated since your last crawl
curl "https://api.menami.mx/api/v1/agent/restaurants?updated_since=2026-05-01T00:00:00Z&limit=100"

Crawl policy

  • Identify yourself in the User-Agent header (e.g., YourCrawler/1.0 (+https://yourcompany.ai/bot)).
  • Default unauthenticated rate limit applies to read endpoints. For higher throughput, register a key. Authenticated requests get 60 req/min by default and you can request a partner tier.
  • Respect Cache-Control headers. The sitemap is cached 5 minutes; restaurant detail and menu responses are stable for at least 60 seconds in the absence of operator edits.
  • We do not require attribution but appreciate "Powered by Menami" badges where your UI surfaces our data.

PARTNER PROGRAM

Partner program: Higher rate limits, webhook push updates, and bulk export are available for search engines, AI labs, and agent platforms. partners@menami.mx.

§ 08

API keys

Self-service key registration. Rate-limited to 5 registrations per IP per hour.

POST/api/v1/agent/keys/registerNo auth

Register your platform and receive an API key instantly. The plaintext key is shown exactly once. Store it securely.

ParamTypeDescription
platform_namerequiredstringHuman-readable name for your agent or platform.
contact_emailrequiredstringEmail we can use to reach you for security advisories.
website_urlstringOptional URL for your product or company.
descriptionstringShort description of what your agent does.
curl -X POST https://api.menami.mx/api/v1/agent/keys/register \
  -H "Content-Type: application/json" \
  -d '{
    "platform_name": "AcmeAgent",
    "contact_email": "dev@acme.ai",
    "website_url": "https://acme.ai",
    "description": "Voice agent for restaurant ordering"
  }'
Response
{
  "key": "ak_live_7f3a9b2c1d4e5f60718293a4b5c6d7e8f",
  "key_prefix": "ak_live_7f3a",
  "platform_name": "AcmeAgent",
  "rate_limit_per_minute": 60
}
§ 09

Checkout endpoints

ACP-compliant checkout flow. All endpoints require an API key via X-Agent-Key and an Idempotency-Key header on POSTs.

POST/api/v1/agent/checkout_sessionsAPI key required

Create a checkout session. The server validates items, resolves modifiers, calculates totals (subtotal, tax, delivery), and returns a session in ready_for_payment state.

Request body
{
  "restaurant_slug": "tacos-el-padrino",
  "currency": "mxn",
  "line_items": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440001",
      "quantity": 3,
      "modifiers": [
        { "group_id": "group-uuid-1", "option_ids": ["mod-3"] }
      ]
    }
  ],
  "customer": {
    "name": "Carlos Martinez",
    "phone": "+525598765432",
    "email": "carlos@example.com"
  },
  "fulfillment_details": {
    "address": {
      "street": "Calle Amsterdam 45, Apt 3B",
      "city": "Mexico City",
      "state": "CDMX",
      "country": "MX",
      "zip": "06100",
      "lat": 19.4126,
      "lng": -99.1703
    }
  },
  "special_instructions": "Ring doorbell twice, second floor"
}
curl -X POST https://api.menami.mx/api/v1/agent/checkout_sessions \
  -H "Content-Type: application/json" \
  -H "X-Agent-Key: $MENAMI_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "restaurant_slug": "tacos-el-padrino",
    "currency": "mxn",
    "line_items": [
      { "id": "550e8400-e29b-41d4-a716-446655440001", "quantity": 3 }
    ],
    "customer": {
      "name": "Carlos Martinez",
      "phone": "+525598765432"
    }
  }'
Response (simplified)
{
  "id": "cs_abc123",
  "status": "ready_for_payment",
  "restaurant_slug": "tacos-el-padrino",
  "currency": "mxn",
  "line_items": [ /* enriched with resolved names + prices */ ],
  "fulfillment_options": [
    { "id": "fo_pickup",   "type": "pickup",         "label": "Pickup" },
    { "id": "fo_delivery", "type": "local_delivery", "label": "Delivery",
      "totals": [{ "amount": 5999, "type": "fulfillment" }], "eta_minutes": 35 }
  ],
  "totals": {
    "subtotal":    17500,
    "tax":          2800,
    "fulfillment":  5999,
    "total":       26299
  },
  "capabilities": {
    "payment": {
      "handlers": [
        { "id": "card_tokenized", "merchant_id": "acct_..." }
      ]
    }
  }
}

All monetary amounts are in minor units (cents for USD, centavos for MXN).

GET/api/v1/agent/checkout_sessions/:idAPI key required

Retrieve the current state of a checkout session.

POST/api/v1/agent/checkout_sessions/:idAPI key required

Update fulfillment selection (e.g., switch from pickup to delivery), line items, or delivery address. The server recalculates totals.

Request body
{
  "selected_fulfillment_options": [
    { "type": "local_delivery", "option_id": "fo_delivery" }
  ]
}
POST/api/v1/agent/checkout_sessions/:id/completeAPI key required

Finalize with a Stripe Shared Payment Token (SPT). The server creates a PaymentIntent on the restaurant's connected account, processes payment, creates the order, and dispatches it to the restaurant's POS or notification flow.

Request body
{
  "payment_data": {
    "handler_id": "card_tokenized",
    "instrument": {
      "type": "card",
      "credential": {
        "type": "spt",
        "token": "spt_abc123..."
      }
    }
  }
}
curl -X POST https://api.menami.mx/api/v1/agent/checkout_sessions/cs_abc123/complete \
  -H "Content-Type: application/json" \
  -H "X-Agent-Key: $MENAMI_KEY" \
  -d '{
    "payment_data": {
      "handler_id": "card_tokenized",
      "instrument": {
        "type": "card",
        "credential": { "type": "spt", "token": "spt_abc123..." }
      }
    }
  }'
Response
{
  "id": "cs_abc123",
  "status": "completed",
  "order": {
    "id": "order-uuid",
    "order_number": "ORD-20260224-XK9F2",
    "permalink_url": "https://tacos-el-padrino.orderin.ai/order/order-uuid",
    "status": "confirmed"
  }
}
POST/api/v1/agent/checkout_sessions/:id/cancelAPI key required

Cancel a checkout session. Optionally include intent_trace for analytics on why the agent abandoned the order.

Request body (optional)
{ "intent_trace": "user_changed_mind" }
§ 10

Utility endpoints

POST/api/v1/agent/delivery/quoteAPI key required

Get a delivery cost estimate and ETA before creating a checkout session. Useful for previewing the delivery fee in a conversational UI.

curl -X POST https://api.menami.mx/api/v1/agent/delivery/quote \
  -H "Content-Type: application/json" \
  -H "X-Agent-Key: $MENAMI_KEY" \
  -d '{
    "restaurant_slug": "tacos-el-padrino",
    "delivery_address": {
      "street": "Calle Amsterdam 45",
      "city": "Mexico City",
      "country": "MX",
      "lat": 19.4126,
      "lng": -99.1703
    }
  }'
Response
{
  "delivery_fee": 5999,
  "currency": "MXN",
  "estimated_minutes": 35,
  "quote_id": "dq_abc123",
  "expires_at": "2026-05-26T08:15:00.000Z"
}

delivery_fee is in minor units (centavos).

GET/api/v1/agent/orders/:orderId/statusAPI key required

Check order status and full status history.

curl https://api.menami.mx/api/v1/agent/orders/$ORDER_ID/status \
  -H "X-Agent-Key: $MENAMI_KEY"
Response
{
  "order_id": "order-uuid",
  "order_number": "ORD-20260224-XK9F2",
  "status": "preparing",
  "status_history": [
    { "status": "confirmed", "at": "2026-02-24T14:30:00Z" },
    { "status": "preparing", "at": "2026-02-24T14:32:00Z" }
  ]
}
§ 11

Webhooks

Register endpoints to receive push notifications for order lifecycle events. No more polling. Every delivery is signed with HMAC-SHA256 so you can trust the payload.

Supported events

EventFires when
order.confirmedPayment captured, order accepted.
order.preparingRestaurant marks the order in the kitchen.
order.readyPickup order is ready for collection.
order.out_for_deliveryDriver has picked up the order.
order.deliveredDelivery driver completed the dropoff.
order.picked_upCustomer picked up a pickup order.
order.canceledRestaurant or customer canceled the order.
POST/api/v1/agent/webhooks/endpointsAPI key required

Register a webhook URL. The plaintext signing secret is returned exactly once. Save it.

ParamTypeDescription
urlrequiredstring (https)Where to POST events. HTTPS required in production.
eventsstring[]Subset of supported events. Defaults to all.
descriptionstringFree-text label shown in the admin dashboard.
curl -X POST https://api.menami.mx/api/v1/agent/webhooks/endpoints \
  -H "Content-Type: application/json" \
  -H "X-Agent-Key: $MENAMI_KEY" \
  -d '{
    "url": "https://yourapp.com/menami-hooks",
    "events": ["order.confirmed", "order.delivered", "order.canceled"],
    "description": "Production order events"
  }'
Response
{
  "id": "wh_abc123",
  "url": "https://yourapp.com/menami-hooks",
  "events": ["order.confirmed", "order.delivered", "order.canceled"],
  "is_active": true,
  "description": "Production order events",
  "created_at": "2026-05-26T08:00:00.000Z",
  "secret": "whsec_8a2b9f1e..."
}
GET/api/v1/agent/webhooks/endpointsAPI key required

List all webhook endpoints registered to your API key. The secret is never returned after creation. If you lose it, delete the endpoint and re-register.

DELETE/api/v1/agent/webhooks/endpoints/:idAPI key required

Permanently delete a webhook endpoint. Returns 204.

Event payload

Every event is a JSON envelope with stable top-level fields:

POST https://yourapp.com/menami-hooks
{
  "id":      "evt_2X9aB1c...",
  "type":    "order.delivered",
  "created": 1716710400,
  "data": {
    "order_id":     "order-uuid",
    "order_number": "ORD-20260526-XK9F2",
    "status":       "delivered",
    "source":       "uber_direct",
    "notes":        null,
    "updated_at":   "2026-05-26T08:00:00.000Z"
  }
}

Verifying the signature

Every request includes:

  • X-Menami-Signature: t=<unix_ts>,v1=<hex_hmac>
  • X-Menami-Event: order.delivered
  • User-Agent: Menami-Webhooks/1.0

Compute HMAC_SHA256(secret, "{t}.{raw_body}") and constant-time compare to the v1 value. Reject if the timestamp drifts more than 5 minutes from your clock (protects against replay). Always verify against the raw request body, not a re-serialized JSON object.

Verify in your handler
import crypto from "crypto";
import express from "express";

const app = express();

// Mount with the raw body so we can verify against the exact bytes Menami signed.
app.post(
  "/menami-hooks",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const header = req.header("x-menami-signature") || "";
    const parts = Object.fromEntries(
      header.split(",").map((kv) => kv.split("="))
    );
    const t = parts.t;
    const v1 = parts.v1;
    const signed = `${t}.${req.body.toString("utf8")}`;
    const expected = crypto
      .createHmac("sha256", process.env.MENAMI_WEBHOOK_SECRET!)
      .update(signed)
      .digest("hex");

    // Constant-time compare; reject if timestamp drifts > 5 min.
    const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
    const valid =
      v1.length === expected.length &&
      crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected));

    if (!fresh || !valid) return res.status(400).send("invalid signature");

    const event = JSON.parse(req.body.toString("utf8"));
    console.log("Received", event.type, event.data.order_id);
    res.status(200).send("ok");
  }
);

Delivery semantics

  • Single best-effort POST with a 5-second timeout. We log every attempt and surface them in your dashboard (and via GET /webhooks/deliveries, coming soon).
  • Idempotency: retries (when shipped) reuse the same id. Treat id as the dedup key.
  • Respond with any 2xx status to acknowledge. Non-2xx responses are logged but do not block order processing.
§ 12

Error handling

All errors return a consistent JSON structure. The code field is stable and machine-readable; error is human-readable and may change.

Error response format
{
  "error": "Human-readable error message",
  "code": "error_code",
  "details": { /* optional, endpoint-specific */ }
}

Common error codes

HTTPCodeDescription
400invalid_requestMissing or invalid request parameters.
400idempotency_key_requiredPOST request missing the Idempotency-Key header.
401unauthorizedMissing or invalid API key.
404not_foundRestaurant, item, session, or order not found.
409conflictIdempotent request already in flight (retry with Retry-After).
422idempotency_conflictSame Idempotency-Key used with a different body.
422out_of_stockOne or more items are unavailable.
422missing_modifierRequired modifier group has no selection.
422below_minimumOrder total below the restaurant minimum.
422restaurant_closedRestaurant is currently closed.
422outside_delivery_zoneDelivery address outside the restaurant range.
402payment_declinedPayment could not be processed (card declined).
429rate_limitedToo many requests. Check Retry-After header.
§ 13

SDKs & integrations

Don't want to write REST code? We ship two first-party clients on npm, and the OpenAPI spec generates idiomatic SDKs in any language.

MCP server

@menami/mcp-server

Drop-in Model Context Protocol server. Works with Claude Desktop, Cursor, Windsurf, and any MCP-compatible agent. 7 tools for recommendations, booking, ordering, feedback.

npx @menami/mcp-server connect

CLI

@menami/cli

Personal food agent for the terminal. Discover, recommend, book, order, all from the command line. Same auth identity (phone number) as the REST API and MCP server.

npm install -g @menami/cli

For language-specific SDKs (Go, Rust, Java, etc.), feed our OpenAPI spec into openapi-generator or your favorite codegen tool.

§ 14

Versioning

We use URL versioning: /api/v1/agent/*. The current major version is v1.

  • Additive changes (new fields, new endpoints, new optional params, new enum values) ship into v1 without notice. Treat the schema as forward-compatible: ignore fields you don't recognize.
  • Breaking changes (renamed fields, removed endpoints, semantic changes) ship as a new major version (v2). We commit to running the previous major in parallel for at least 12 months after a new one is announced.
  • Deprecations are announced via email to every registered contact_email, listed in the Changelog, and surfaced on affected endpoints via a Deprecation response header.
  • The OpenAPI spec is the source of truth. Lock to api.menami.mx/openapi.yaml?v=1 for stable codegen.
§ 15

Pricing & quotas

During the v1 launch period the Agent Protocol is free to use for all registered partners. The economic model is per-order revenue share with the restaurant. Agents don't pay us; restaurants pay Menami a platform fee that's already baked into the totals you see (and into the Stripe split).

TierRate limitSitemap throughputHow to get it
Self-serve60 req/minDefault catalog scrapePOST /keys/register
Verified partner600 req/minBulk export availablepartners@menami.mx
EnterpriseCustomS3 dump + webhookspartners@menami.mx

Verified-partner tier

Verified-partner status unlocks 10× rate limits, a higher per-IP key registration cap, early access to roadmap endpoints (webhook delivery logs, S3 catalog export), and a direct Slack channel with engineering. Eligibility: a published product or research paper that uses our data, plus a stable contact channel. Email partners@menami.mx with your platform name, contact_email used in registration, and a sentence on what you're building.

Fair-use policy

We don't bill for API access, but we do throttle abusive patterns: repeated 4xx loops, scraping past the documented rate limits, registering many keys to circumvent limits, or unauthenticated catalog dumps faster than once per hour. If you need a higher ceiling, just ask. Almost every legitimate request gets approved.

§ 16

Changelog

Material changes to the API surface. Additive entries are released without notice; breaking entries get a 12-month grace period (see Versioning).

2026-05-28v1.1release
  • Webhooks. New POST /webhooks/endpoints, signed HMAC-SHA256 delivery for all order.* lifecycle events. Partners no longer need to poll.
  • Test mode. Self-serve ak_test_* keys via mode: "test" on registration. Skip Stripe entirely while integrating.
  • Cursor pagination. starting_after plus next_cursor on GET /restaurants for stable iteration.
  • Minor units everywhere. All monetary fields (delivery_fee, min_order_amount, price, price_adjustment) now return integer minor units (cents/centavos). Breaking for any clients that were depending on major-unit decimals. The prior behavior is preserved on the deprecated /api/v0/agent/* shadow until 2027-05-28.
  • X-Request-Id. Every response now carries a correlation header. Send your own to thread context through your stack.
2026-05-26v1.0release
  • Public launch. /api/v1/agent opens for self-serve registration.
  • Indexing affordances. GET /sitemap.json, updated_since filter, and schema_org JSON-LD on restaurant detail.
  • OpenAPI 3.1 spec published at api.menami.mx/openapi.yaml.

END OF EDITION

Ready to integrate?

Get an API key and start building agent-powered ordering, search, or recommendations against 12,000+ restaurants.

Last updated 2026-05-28 · v1.1 · OpenAPI 3.1 spec