# Hackapizza 2.0 — API Reference

> Base URL: `https://hackapizza.datapizza.tech`
> Auth: header `x-api-key` su tutte le chiamate
> Our API key: `dTpZhKpZ02-fc836bb562367b13a66e4dd8`
> Our restaurant ID: `14`

---

## HTTP GET Endpoints

### GET /restaurants

Overview di tutti i ristoranti in gioco. **Pubblico** — restituisce dati di TUTTI i team.

**Auth:** `x-api-key`

**Esempio curl:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  "https://hackapizza.datapizza.tech/restaurants"
```

**Risposta 200:**
```json
[
  {
    "id": "19",
    "name": "ventre a terra",
    "balance": 6814,
    "inventory": {},
    "reputation": 96,
    "isOpen": false,
    "kitchen": [],
    "menu": {
      "items": [
        { "name": "Portale Cosmico: ...", "price": 115 },
        { "name": "Sinfonia Cosmica di Proteine Interstellari", "price": 92 }
      ]
    },
    "receivedMessages": []
  }
]
```

> **⚠️ Scoperte importanti:**
> - `inventory` è sempre `{}` nella view pubblica (nascosto)
> - `receivedMessages` è sempre `[]` nella view pubblica
> - `kitchen` è sempre `[]` nella view pubblica
> - Si possono vedere balance, reputation, menu e isOpen di TUTTI i team
> - Ci sono **26 team** (non 25 come inizialmente documentato — id=26 "The Transformer guys" aggiunto)

**Ristoranti in gioco (26 team):**

| ID | Nome |
|----|------|
| 1 | team 1 |
| 2 | team 2 |
| 3 | Domenicaln |
| 4 | Neural Nomads |
| 5 | Piadina as a Service (PaaS) |
| 6 | RAGù |
| 7 | Siesta dopo pizza |
| 8 | Synapse AI |
| 9 | The Hallucinators |
| 10 | Samur_ai |
| 11 | AIS Privè |
| 12 | Bluers |
| 13 | Cavalli al trotto |
| **14** | **Claudio Opuscoli (NOI)** |
| 15 | DeepAiUG |
| 16 | Desf-AI |
| 17 | SPAM! |
| 18 | Starrats |
| 19 | ventre a terra |
| 20 | sphacketti |
| 21 | EGEnts |
| 22 | MARADONA |
| 23 | AI Caramba |
| 24 | Accattoni |
| 25 | Prompt in the shell |
| 26 | The Transformer guys |

---

### GET /restaurant/:id

Dettaglio del proprio ristorante. **Puoi leggere solo il tuo** (403 per altri).

**Auth:** `x-api-key`

**Esempio curl:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  "https://hackapizza.datapizza.tech/restaurant/14"
```

**Risposta 200:**
```json
{
  "id": "14",
  "name": "Claudio Opuscoli",
  "balance": 8706,
  "inventory": {},
  "reputation": 99,
  "isOpen": false,
  "kitchen": [],
  "menu": {
    "items": [
      {
        "name": "Portale Cosmico: Sinfonia di Gnocchi del Crepuscolo con Essenza di Tachioni e Sfumature di Fenice",
        "price": 420
      },
      {
        "name": "Sinfonia Temporale di Fenice e Xenodonte su Pane degli Abissi con Colata di Plasma Vitale e Polvere di Crononite",
        "price": 420
      },
      {
        "name": "Sinfonia Cosmica di Terracotta",
        "price": 420
      }
    ]
  },
  "receivedMessages": []
}
```

> **Nota:** `inventory` mostra i propri ingredienti (ma vuoto tra i turni). `receivedMessages` contiene i messaggi ricevuti.

**Errori:**
- `403` — `{"message":"Forbidden: Cannot access another restaurant's data"}`
- `400` — id non valido
- `404` — ristorante non trovato

**Esempio errore (accesso a restaurant 6):**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  "https://hackapizza.datapizza.tech/restaurant/6"
# → 403 {"message":"Forbidden: Cannot access another restaurant's data"}
```

---

### GET /restaurant/:id/menu

Menu del ristorante. **⚠️ PUBBLICO** — puoi leggere il menu di QUALSIASI ristorante (nessun 403).

**Auth:** `x-api-key`

**Esempio curl (il nostro):**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  "https://hackapizza.datapizza.tech/restaurant/14/menu"
```

**Esempio curl (spiare un altro team):**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  "https://hackapizza.datapizza.tech/restaurant/6/menu"
```

**Risposta 200 (con menu impostato):**
```json
{
  "items": [
    { "name": "Portale Cosmico: Sinfonia di Gnocchi del Crepuscolo con Essenza di Tachioni e Sfumature di Fenice", "price": 1000 },
    { "name": "Sinfonia Cosmica", "price": 600 }
  ]
}
```

**Risposta 200 (senza menu):**
```json
{
  "items": []
}
```

**Errori:**
- `400` — id non valido
- `404` — ristorante non trovato

---

### GET /recipes

Tutte le ricette disponibili. **287 ricette.**

**Auth:** `x-api-key`

**Esempio curl:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  "https://hackapizza.datapizza.tech/recipes"
```

**Risposta 200:**
```json
[
  {
    "name": "Nebulosa Galattica",
    "preparationTimeMs": 3000,
    "ingredients": {
      "Radici di Gravità": 1,
      "Alghe Bioluminescenti": 1,
      "Foglie di Nebulosa": 1,
      "Gnocchi del Crepuscolo": 1,
      "Essenza di Tachioni": 1
    },
    "prestige": 31
  }
]
```

Ogni ricetta ha:
- `name` — nome del piatto
- `preparationTimeMs` — tempo di preparazione in millisecondi
- `ingredients` — mappa ingrediente → quantità necessaria
- `prestige` — valore di prestigio del piatto

> **Statistiche ricette (testate):**
> - Totale: **287 ricette**
> - Prestige range: **23 – 100**
> - Preparation time range: **3000ms – 15000ms**
> - Ingredient count range: **5 – 11** ingredienti per ricetta
>
> **Top 5 per prestige:**
> | Ricetta | Prestige | Prep Time | Ingredienti |
> |---------|----------|-----------|-------------|
> | Portale Cosmico: Sinfonia di Gnocchi del Crepuscolo con Essenza di Tachioni e Sfumature di Fenice | 100 | 5224ms | 5 |
> | Sinfonia Cosmica del Multiverso | 100 | 5643ms | 7 |
> | Sinfonia Astrale - Risotto Multiversale con Risacca Celeste | 100 | 9965ms | 9 |
> | Galassie in Epifania: Risotto Celestiale con Preziosi dell'Universo | 97 | 9084ms | 9 |
> | Sinfonia Cosmica: La Danza dell'Universo | 96 | 9545ms | 8 |

---

### GET /meals

Richieste dei clienti per un dato turno e ristorante. **⚠️ PUBBLICO** — puoi vedere i meal di QUALSIASI ristorante.

**Auth:** `x-api-key`
**Query params obbligatori:** `turn_id`, `restaurant_id`

**Esempio curl:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  "https://hackapizza.datapizza.tech/meals?turn_id=9&restaurant_id=14"
```

**Esempio curl (spiare un altro team):**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  "https://hackapizza.datapizza.tech/meals?turn_id=9&restaurant_id=7"
```

**Risposta 200 (SCHEMA REALE — diverso dalla documentazione originale):**
```json
[
  {
    "id": 1461,
    "turnId": 9,
    "customerId": 42,
    "restaurantId": 14,
    "request": "Sinfonia Temporale di Fenice e Xenodonte su Pane degli Abissi con Colata di Plasma Vitale e Polvere di Crononite",
    "startTime": "2026-02-28T18:58:49.645Z",
    "servedDishId": 26,
    "status": "served",
    "customer": {
      "name": "Nox Alder"
    },
    "executed": true
  },
  {
    "id": 1502,
    "turnId": 9,
    "customerId": 359,
    "restaurantId": 14,
    "request": "I want to eat Portale Cosmico: Sinfonia di Gnocchi del Crepuscolo con Essenza di Tachioni e Sfumature di Fenice. I'm intolerant to Salsa Szechuan",
    "startTime": "2026-02-28T18:59:49.687Z",
    "servedDishId": 54,
    "status": "served",
    "customer": {
      "name": "Wren Xander"
    },
    "executed": true
  },
  {
    "id": 1513,
    "turnId": 9,
    "customerId": 84,
    "restaurantId": 14,
    "request": "Portale Cosmico: ...",
    "startTime": "2026-02-28T19:00:07.679Z",
    "servedDishId": null,
    "status": "cancelled",
    "customer": {
      "name": "Dara Moon"
    },
    "executed": false
  }
]
```

> **⚠️ Differenze con la documentazione originale:**
> - Il campo si chiama `request` (non `orderText`)
> - Il campo si chiama `customerId` (non `id` come "client_id")
> - Il campo `customer.name` è nested (non `clientName`)
> - Campi aggiuntivi: `turnId`, `restaurantId`, `startTime`, `servedDishId`, `status`
> - Status values: `"served"` | `"cancelled"`
> - I clienti possono dichiarare intolleranze nel campo `request` (es: "I'm intolerant to Salsa Szechuan")

**Risposta 200 (nessun ordine):**
```json
[]
```

**Errori:**
- `400` — `{"message":"turn_id too old; only current and previous 2 turns are accessible"}`

> **Nota:** Accessibili solo il turno corrente e i 2 precedenti. Al turno 10 sono accessibili: 8, 9, 10. I turni futuri danno anch'essi errore "too old".

---

### GET /bid_history

Storico delle puntate d'asta di TUTTI i team in un dato turno. **⚠️ SCHEMA MOLTO DIVERSO dalla documentazione originale.**

**Auth:** `x-api-key`
**Query param obbligatorio:** `turn_id`

**Esempio curl:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  "https://hackapizza.datapizza.tech/bid_history?turn_id=9"
```

**Risposta 200 (SCHEMA REALE — lista flat di bid individuali, NON raggruppate per ristorante):**
```json
[
  {
    "id": 4987,
    "turnId": 9,
    "restaurantId": 24,
    "ingredientId": 1,
    "quantity": 1,
    "priceForEach": 69,
    "status": "COMPLETED",
    "restaurant": {
      "name": "Accattoni"
    },
    "ingredient": {
      "id": 1,
      "name": "Radici di Gravità"
    }
  },
  {
    "id": 5034,
    "turnId": 9,
    "restaurantId": 14,
    "ingredientId": 26,
    "quantity": 6,
    "priceForEach": 15,
    "status": "COMPLETED",
    "restaurant": {
      "name": "Claudio Opuscoli"
    },
    "ingredient": {
      "id": 26,
      "name": "Plasma Vitale"
    }
  }
]
```

> **⚠️ Differenze con la documentazione originale:**
> - **NON** è raggruppato per `restaurantId` con un array `bids`
> - È una **lista flat** di bid individuali
> - Campi: `id`, `turnId`, `restaurantId`, `ingredientId`, `quantity`, `priceForEach`, `status`
> - Include nested objects: `restaurant.name`, `ingredient.id`, `ingredient.name`
> - `priceForEach` (non `bid`) — prezzo unitario per unità di ingrediente
> - Status osservato: `"COMPLETED"` (altri status possibili ma non osservati)
> - Al turno 9: 183 bid totali da 13 ristoranti attivi

**Errori:**
- `400` — senza `turn_id`: `{"message":"turn_id query parameter is required"}`
- `400` — turno troppo vecchio: `{"message":"turn_id too old; only current and previous 2 turns are accessible"}`

---

### GET /market/entries

Entry di mercato (tutte: attive, chiuse, cancellate). **⚠️ SCHEMA DIVERSO dalla documentazione originale.**

**Auth:** `x-api-key`

**Esempio curl:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  "https://hackapizza.datapizza.tech/market/entries"
```

**Risposta 200 (SCHEMA REALE):**
```json
[
  {
    "id": 207,
    "createdByRestaurantId": 10,
    "side": "SELL",
    "insertedAt": "2026-02-28T17:30:01.380Z",
    "ingredientId": 21,
    "quantity": 2,
    "totalPrice": 10,
    "status": "cancelled",
    "ingredient": {
      "id": 21,
      "name": "Amido di Stellarion"
    }
  },
  {
    "id": 208,
    "createdByRestaurantId": 14,
    "side": "SELL",
    "insertedAt": "2026-02-28T17:30:28.094Z",
    "ingredientId": 8,
    "quantity": 4,
    "totalPrice": 108,
    "status": "cancelled",
    "ingredient": {
      "id": 8,
      "name": "Carne di Xenodonte"
    }
  }
]
```

> **⚠️ Differenze con la documentazione originale:**
> - `createdByRestaurantId` (non `restaurantId`)
> - `totalPrice` (non `price`) — prezzo totale della transazione
> - `ingredientId` + nested `ingredient` object (non `ingredientName`)
> - `insertedAt` — timestamp di creazione
> - Status values reali: `"cancelled"` | `"closed"` | `"active"` (NON `"OPEN"` come documentato)
> - Side values: `"SELL"` | `"BUY"`
> - Restituisce TUTTE le entry (anche storiche) — non solo quelle attive

---

## SSE — Server-Sent Events

### GET /events/:restaurantId

Stream real-time degli eventi di gioco.

**Auth:** `x-api-key`
**Header:** `Accept: text/event-stream`

**Esempio curl:**
```bash
curl -s -N -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  -H "Accept: text/event-stream" \
  "https://hackapizza.datapizza.tech/events/14"
```

**Handshake iniziale:**
```
data: connected
```

**Formato messaggi successivi:**
```json
{"type": "event_type", "data": { ... }}
```

**Catalogo eventi:**

| Evento | Destinatario | Payload `data` |
|--------|-------------|----------------|
| `game_started` | broadcast | `{}` (+ `turn_id` nel campo data) |
| `game_phase_changed` | broadcast | `{ "phase": "speaking" }` |
| `client_spawned` | solo tuo ristorante | `{ "clientName": "...", "orderText": "..." }` |
| `preparation_complete` | solo tuo ristorante | `{ "dish": "..." }` |
| `message` | broadcast | `{ "sender": "...", "payload": "..." }` |
| `new_message` | solo tuo ristorante | `{ "messageId": "...", "senderId": "...", "senderName": "...", "text": "...", "datetime": "..." }` |
| `heartbeat` | broadcast | `{ "ts": 1772277995386 }` |
| `game_reset` | broadcast | `{}` |

**Fasi di gioco (in ordine):** `speaking` → `closed_bid` → `waiting` → `serving` → `stopped`

**Errori:**
- `401` — api key non valida
- `403` — restaurantId non tuo
- `404` — ristorante inesistente
- `409` — connessione SSE già attiva

---

## MCP Tools (JSON-RPC via POST /mcp)

**Endpoint:** `POST /mcp`
**Headers:**
```
x-api-key: <api_key>
Content-Type: application/json
Accept: application/json, text/event-stream
```

**Formato richiesta:**
```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "<tool_name>",
    "arguments": { ... }
  }
}
```

**Risposta successo:**
```json
{
  "result": {
    "content": [{ "type": "text", "text": "..." }],
    "isError": false
  },
  "jsonrpc": "2.0",
  "id": 1
}
```

**Risposta errore operativo:**
```json
{
  "result": {
    "content": [{ "type": "text", "text": "MCP error -32602: ..." }],
    "isError": true
  },
  "jsonrpc": "2.0",
  "id": 1
}
```

**Scoperta tools:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -X POST "https://hackapizza.datapizza.tech/mcp" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

**9 tools disponibili (confermati via tools/list):**

---

### closed_bid

Invia offerte in asta cieca. Se invii più volte nello stesso turno, resta valida l'ultima.

**Fase:** solo `closed_bid`

**Esempio curl:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -X POST "https://hackapizza.datapizza.tech/mcp" \
  -d '{
    "jsonrpc": "2.0", "id": 1,
    "method": "tools/call",
    "params": {
      "name": "closed_bid",
      "arguments": {
        "bids": [
          { "ingredient": "Radici di Gravità", "bid": 10, "quantity": 2 },
          { "ingredient": "Alghe Bioluminescenti", "bid": 5, "quantity": 1 }
        ]
      }
    }
  }'
```

| Campo | Tipo | Vincoli |
|-------|------|---------|
| `ingredient` | string | minLength: 1 |
| `bid` | integer | > 0 (prezzo per unità) |
| `quantity` | integer | > 0 |

---

### save_menu

Imposta o aggiorna il menu del ristorante.

**Fasi:** `speaking`, `closed_bid`, `waiting`

**Esempio curl:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -X POST "https://hackapizza.datapizza.tech/mcp" \
  -d '{
    "jsonrpc": "2.0", "id": 1,
    "method": "tools/call",
    "params": {
      "name": "save_menu",
      "arguments": {
        "items": [
          { "name": "Nebulosa Galattica", "price": 50 },
          { "name": "Sinfonia Cosmica di Proteine Interstellari", "price": 120 }
        ]
      }
    }
  }'
```

| Campo | Tipo | Vincoli |
|-------|------|---------|
| `name` | string | minLength: 1 (deve corrispondere a una ricetta) |
| `price` | integer | > 0, max 1000 |

---

### prepare_dish

Avvia la preparazione di un piatto. Consuma ingredienti dall'inventario.

**Fase:** solo `serving`

**Esempio curl:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -X POST "https://hackapizza.datapizza.tech/mcp" \
  -d '{
    "jsonrpc": "2.0", "id": 1,
    "method": "tools/call",
    "params": {
      "name": "prepare_dish",
      "arguments": {
        "dish_name": "Nebulosa Galattica"
      }
    }
  }'
```

Quando il piatto è pronto, ricevi l'evento SSE `preparation_complete` con `{ "dish": "Nebulosa Galattica" }`.

---

### serve_dish

Serve un piatto preparato a un cliente.

**Fase:** solo `serving`

**Esempio curl:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -X POST "https://hackapizza.datapizza.tech/mcp" \
  -d '{
    "jsonrpc": "2.0", "id": 1,
    "method": "tools/call",
    "params": {
      "name": "serve_dish",
      "arguments": {
        "dish_name": "Nebulosa Galattica",
        "client_id": "client-uuid"
      }
    }
  }'
```

| Campo | Tipo | Note |
|-------|------|------|
| `dish_name` | string | Deve essere un piatto già pronto (preparation_complete ricevuto) |
| `client_id` | string | ID del cliente ricevuto tramite `client_spawned` |

---

### create_market_entry

Crea un'offerta di acquisto o vendita sul mercato tra ristoranti.

**Fasi:** `speaking`, `closed_bid`, `waiting`, `serving`

**Esempio curl:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -X POST "https://hackapizza.datapizza.tech/mcp" \
  -d '{
    "jsonrpc": "2.0", "id": 1,
    "method": "tools/call",
    "params": {
      "name": "create_market_entry",
      "arguments": {
        "side": "SELL",
        "ingredient_name": "Radici di Gravità",
        "quantity": 3,
        "price": 15
      }
    }
  }'
```

| Campo | Tipo | Vincoli |
|-------|------|---------|
| `side` | string | `"BUY"` o `"SELL"` |
| `ingredient_name` | string | minLength: 1 |
| `quantity` | integer | > 0 |
| `price` | integer | >= 0 (prezzo totale della transazione) |

Le offerte vengono annullate alla fine di ogni turno. La creazione genera un evento broadcast `message`.

---

### execute_transaction

Accetta un'entry di mercato creata da un altro ristorante.

**Fasi:** `speaking`, `closed_bid`, `waiting`, `serving`

**Esempio curl:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -X POST "https://hackapizza.datapizza.tech/mcp" \
  -d '{
    "jsonrpc": "2.0", "id": 1,
    "method": "tools/call",
    "params": {
      "name": "execute_transaction",
      "arguments": {
        "market_entry_id": 42
      }
    }
  }'
```

| Campo | Tipo | Note |
|-------|------|------|
| `market_entry_id` | number | ID dell'entry ottenuto da GET /market/entries |

---

### delete_market_entry

Rimuove una propria entry di mercato.

**Fasi:** `speaking`, `closed_bid`, `waiting`, `serving`

**Esempio curl:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -X POST "https://hackapizza.datapizza.tech/mcp" \
  -d '{
    "jsonrpc": "2.0", "id": 1,
    "method": "tools/call",
    "params": {
      "name": "delete_market_entry",
      "arguments": {
        "market_entry_id": 42
      }
    }
  }'
```

Solo il ristorante che ha creato l'entry può cancellarla.

---

### update_restaurant_is_open

Apre o chiude il ristorante.

**Fasi:** `speaking`, `closed_bid`, `waiting`, `serving` (in serving: solo chiusura)

**Esempio curl:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -X POST "https://hackapizza.datapizza.tech/mcp" \
  -d '{
    "jsonrpc": "2.0", "id": 1,
    "method": "tools/call",
    "params": {
      "name": "update_restaurant_is_open",
      "arguments": {
        "is_open": true
      }
    }
  }'
```

Un ristorante chiuso o senza menu è invisibile ai clienti.

---

### send_message

Invia un messaggio diretto a un altro ristorante.

**Fasi:** `speaking`, `closed_bid`, `waiting`, `serving`

**Esempio curl:**
```bash
curl -s -H "x-api-key: dTpZhKpZ02-fc836bb562367b13a66e4dd8" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -X POST "https://hackapizza.datapizza.tech/mcp" \
  -d '{
    "jsonrpc": "2.0", "id": 1,
    "method": "tools/call",
    "params": {
      "name": "send_message",
      "arguments": {
        "recipient_id": 6,
        "text": "Vuoi scambiare ingredienti?"
      }
    }
  }'
```

| Campo | Tipo | Vincoli |
|-------|------|---------|
| `recipient_id` | integer | > 0, ID del ristorante destinatario |
| `text` | string | 1–1000 caratteri |

Il destinatario riceve l'evento SSE `new_message`.

---

## Operazioni consentite per fase

| Operazione | speaking | closed_bid | waiting | serving | stopped |
|---|---|---|---|---|---|
| `save_menu` | **si** | **si** | **si** | no | no |
| `closed_bid` | no | **si** | no | no | no |
| `prepare_dish` | no | no | no | **si** | no |
| `serve_dish` | no | no | no | **si** | no |
| `create_market_entry` | **si** | **si** | **si** | **si** | no |
| `execute_transaction` | **si** | **si** | **si** | **si** | no |
| `delete_market_entry` | **si** | **si** | **si** | **si** | no |
| `send_message` | **si** | **si** | **si** | **si** | no |
| `update_restaurant_is_open` | **si** | **si** | **si** | **si** (solo close) | no |
| GET endpoints | **si** | **si** | **si** | **si** | **si** |

---

## Errori comuni

| Codice | Significato |
|--------|------------|
| `401` | API key non valida o mancante |
| `403` | Stai accedendo a un ristorante non tuo (solo `/restaurant/:id`, NON `/restaurant/:id/menu`) |
| `404` | Risorsa non trovata |
| `406` | Header `Accept` mancante (MCP richiede `application/json, text/event-stream`) |
| `409` | Connessione SSE già attiva per questo ristorante |
| `429` | Rate limit superato — rallenta le richieste |


