Template gallery / menu

menu

Restaurant menu on A4 or Letter: sections with dish, description, dietary marks and price, optional two-column layout, a wine-by-the-glass block, and a footnote line. Sections never split mid-heading.

chromium default PDF 15 top-level fields 1 unit per page

Rendered preview of the menu template
Rendered by Galley from the example payload below, at 816px wide , scale 2.

Fields

The full JSON Schema is below. Required fields are marked; anything missing comes back as a 422 naming the path, the expected type and a value that would be accepted.

Field Type Required Description
title string optional The menu's own name, under the restaurant name.
served string optional
currency string optional
columns 1 | 2 | 3 optional Column count for the sections.
accent string optional
paper string optional Sheet background.
text_color string optional
muted_color string optional
rule_color string optional
notes string optional
pours_title string optional
restaurant object { name, address, phone, website, … } required
sections array of object { name, blurb, items } required
pours array of object { name, detail, glass_price, bottle_price } optional Wine or cocktail list in its own bordered block.
dietary_key array of object { mark, meaning } optional

Default render options

Applied unless you override them. Options are part of the cache key.

page_size "Letter"
margin "0.6in"
print_background true

Example payload

This exact object renders the preview above. It is also what the API echoes back in a validation error, so an agent can repair a payload without a round trip to the docs.

example.jsonjson
{
  "title": "Dinner",
  "served": "Served Tuesday through Sunday, 5pm to 10pm",
  "currency": "USD",
  "columns": 2,
  "accent": "#7c2d12",
  "restaurant": {
    "name": "The Salt Line",
    "address": "11 South Second St, Fernandina Beach, FL",
    "phone": "(904) 555-0119",
    "website": "saltline.test"
  },
  "sections": [
    {
      "name": "To start",
      "blurb": "Meant for the middle of the table.",
      "items": [
        {
          "name": "Mayport shrimp toast",
          "description": "Cultured butter, preserved lemon, fennel fronds, grilled sourdough",
          "price": 18,
          "marks": [
            "N"
          ]
        },
        {
          "name": "Oysters on the half shell",
          "description": "Amelia River, mignonette, horseradish — half dozen",
          "price": 21,
          "marks": [
            "GF",
            "R"
          ]
        },
        {
          "name": "Chilled green tomato soup",
          "description": "Buttermilk, dill oil, cucumber, toasted benne",
          "price": 13,
          "marks": [
            "V",
            "GF"
          ]
        },
        {
          "name": "Smoked mullet dip",
          "description": "House crackers, pickled okra, hot honey",
          "price": 16
        }
      ]
    },
    {
      "name": "From the water",
      "items": [
        {
          "name": "Whole roasted snapper",
          "description": "Charred scallion, brown butter, lime, herb salad — for two",
          "price_text": "MP",
          "marks": [
            "GF"
          ]
        },
        {
          "name": "Seared cobia",
          "description": "Field pea succotash, tomato broth, basil",
          "price": 38
        },
        {
          "name": "Shrimp and grits",
          "description": "Anson Mills grits, tasso, sweet pepper gravy",
          "price": 32
        },
        {
          "name": "Fried flounder sandwich",
          "description": "Tartar, shaved cabbage, sesame bun, salt vinegar chips",
          "price": 24
        }
      ]
    },
    {
      "name": "From the land",
      "items": [
        {
          "name": "Coal-roasted half chicken",
          "description": "Sorghum glaze, collards, cornbread crumb",
          "price": 34
        },
        {
          "name": "Dry-aged strip",
          "description": "Twelve ounces, bone marrow butter, watercress",
          "price": 62,
          "marks": [
            "GF"
          ]
        },
        {
          "name": "Charred cabbage steak",
          "description": "Peanut romesco, crispy shallot, herbs",
          "price": 26,
          "marks": [
            "V",
            "N"
          ]
        }
      ]
    },
    {
      "name": "Sides",
      "items": [
        {
          "name": "Skillet cornbread",
          "description": "Whipped honey butter",
          "price": 9,
          "marks": [
            "V"
          ]
        },
        {
          "name": "Charred okra",
          "description": "Lemon, chili, bonito",
          "price": 11,
          "marks": [
            "GF"
          ]
        },
        {
          "name": "Rice middlins",
          "description": "Brown butter, thyme",
          "price": 10,
          "marks": [
            "V",
            "GF"
          ]
        }
      ]
    },
    {
      "name": "To finish",
      "items": [
        {
          "name": "Buttermilk pie",
          "description": "Blackberry, cane syrup, crème fraîche",
          "price": 12,
          "marks": [
            "V"
          ]
        },
        {
          "name": "Salted chocolate cremeux",
          "description": "Olive oil, sea salt, sourdough crumb",
          "price": 13,
          "marks": [
            "V"
          ]
        },
        {
          "name": "Citrus granita",
          "description": "Amelia satsuma, mint",
          "price": 9,
          "marks": [
            "V",
            "GF"
          ]
        }
      ]
    }
  ],
  "pours": [
    {
      "name": "Muscadet, Domaine de la Pépière",
      "detail": "Loire Valley, France — 2024",
      "glass_price": 14,
      "bottle_price": 52
    },
    {
      "name": "Vermentino, Tenuta Argentiera",
      "detail": "Tuscany, Italy — 2023",
      "glass_price": 16,
      "bottle_price": 60
    },
    {
      "name": "Cinsault, Broc Cellars",
      "detail": "Sonoma County, California — 2024",
      "glass_price": 17,
      "bottle_price": 64
    },
    {
      "name": "Fino sherry, Bodegas Tradición",
      "detail": "Jerez, Spain — NV",
      "glass_price": 15
    },
    {
      "name": "Amelia highball",
      "detail": "Rye, satsuma cordial, soda",
      "glass_price": 15
    }
  ],
  "dietary_key": [
    {
      "mark": "V",
      "meaning": "vegetarian"
    },
    {
      "mark": "GF",
      "meaning": "gluten free"
    },
    {
      "mark": "N",
      "meaning": "contains nuts"
    },
    {
      "mark": "R",
      "meaning": "served raw"
    }
  ],
  "notes": "Consuming raw or undercooked seafood may increase your risk of foodborne illness. A 20% service charge is added to parties of six or more."
}

Render it

With an API keyshell
curl -sS https://api.galleyrender.com/v1/render \
  -H "Authorization: Bearer $GALLEY_API_KEY" \
  -H 'content-type: application/json' \
  -d '{
  "template": "menu@1",
  "format": "pdf",
  "data": "… the example payload above …"
}'
With no API key, over MCPshell
# No API key. The first call mints a 50-render trial.
curl -sS https://mcp.galleyrender.com/mcp \
  -H 'content-type: application/json' \
  -H 'accept: application/json, text/event-stream' \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "render",
      "arguments": {
        "template": "menu",
        "format": "pdf",
        "data": { … see the example payload above … }
      }
    }
  }'

Pin the version — menu@1 — in anything you ship. Publishing a new version never changes an old one. Render endpoint reference →

Try a free tool

Renders the example payload on the production service. No account, no key.

JSON Schema

schema.json (15 top-level properties)
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Menu",
  "type": "object",
  "required": [
    "restaurant",
    "sections"
  ],
  "additionalProperties": true,
  "properties": {
    "title": {
      "type": "string",
      "description": "The menu's own name, under the restaurant name.",
      "examples": [
        "Dinner"
      ]
    },
    "served": {
      "type": "string",
      "examples": [
        "Served Tuesday through Sunday, 5pm to 10pm"
      ]
    },
    "currency": {
      "type": "string",
      "default": "USD",
      "examples": [
        "USD"
      ]
    },
    "columns": {
      "type": "integer",
      "enum": [
        1,
        2,
        3
      ],
      "default": 2,
      "description": "Column count for the sections.",
      "examples": [
        2
      ]
    },
    "accent": {
      "type": "string",
      "examples": [
        "#7c2d12"
      ]
    },
    "paper": {
      "type": "string",
      "description": "Sheet background.",
      "examples": [
        "#fdfbf7"
      ]
    },
    "text_color": {
      "type": "string",
      "examples": [
        "#1c1a17"
      ]
    },
    "muted_color": {
      "type": "string",
      "examples": [
        "#7a7268"
      ]
    },
    "rule_color": {
      "type": "string",
      "examples": [
        "#ded7cc"
      ]
    },
    "notes": {
      "type": "string",
      "examples": [
        "Consuming raw or undercooked seafood may increase your risk of foodborne illness. A 20% service charge is added to parties of six or more."
      ]
    },
    "pours_title": {
      "type": "string",
      "default": "By the glass",
      "examples": [
        "By the glass"
      ]
    },
    "restaurant": {
      "type": "object",
      "required": [
        "name"
      ],
      "properties": {
        "name": {
          "type": "string",
          "examples": [
            "The Salt Line"
          ]
        },
        "address": {
          "type": "string",
          "examples": [
            "11 South Second St, Fernandina Beach, FL"
          ]
        },
        "phone": {
          "type": "string",
          "examples": [
            "(904) 555-0119"
          ]
        },
        "website": {
          "type": "string",
          "examples": [
            "saltline.test"
          ]
        },
        "logo_url": {
          "type": "string",
          "format": "uri",
          "examples": [
            "https://example.com/logo.png"
          ]
        }
      }
    },
    "sections": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "required": [
          "name",
          "items"
        ],
        "properties": {
          "name": {
            "type": "string",
            "examples": [
              "To start"
            ]
          },
          "blurb": {
            "type": "string",
            "examples": [
              "Everything here is meant for the middle of the table."
            ]
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "name"
              ],
              "properties": {
                "name": {
                  "type": "string",
                  "examples": [
                    "Mayport shrimp toast"
                  ]
                },
                "description": {
                  "type": "string",
                  "examples": [
                    "Cultured butter, preserved lemon, fennel fronds, grilled sourdough"
                  ]
                },
                "price": {
                  "type": "number",
                  "minimum": 0,
                  "examples": [
                    18
                  ]
                },
                "price_text": {
                  "type": "string",
                  "description": "Use instead of price for things like \"MP\".",
                  "examples": [
                    "MP"
                  ]
                },
                "marks": {
                  "type": "array",
                  "description": "Short dietary marks matched by dietary_key.",
                  "items": {
                    "type": "string",
                    "examples": [
                      "GF"
                    ]
                  },
                  "examples": [
                    [
                      "GF",
                      "N"
                    ]
                  ]
                }
              }
            }
          }
        }
      }
    },
    "pours": {
      "type": "array",
      "description": "Wine or cocktail list in its own bordered block.",
      "items": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "examples": [
              "Muscadet, Domaine de la Pépière"
            ]
          },
          "detail": {
            "type": "string",
            "examples": [
              "Loire Valley, France — 2024"
            ]
          },
          "glass_price": {
            "type": "number",
            "minimum": 0,
            "examples": [
              14
            ]
          },
          "bottle_price": {
            "type": "number",
            "minimum": 0,
            "examples": [
              52
            ]
          }
        }
      }
    },
    "dietary_key": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "mark",
          "meaning"
        ],
        "properties": {
          "mark": {
            "type": "string",
            "examples": [
              "GF"
            ]
          },
          "meaning": {
            "type": "string",
            "examples": [
              "gluten free"
            ]
          }
        }
      }
    }
  }
}