Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help


title: Birthday Add-On API Contract description: V5 birthday add-on response fields and Pegasus visibility rules.

Implementation target repository: hungryhub-team/hh-pegasus-monorepo.

Backend contract source: src/HHServer/superpowers/plans/2026-07-30-birthday-add-on-hh-server.md.

V5 endpoints

Pegasus calls the V5 API with the locale in the shared HTTP context. The API receives these parameters after camelCase-to-snake_case conversion:

Add-on list

GET /api/v5/add_on_packages.json
  ?restaurant_id=<restaurant-id>
  &is_visible_for_staff=false

is_visible_for_staff defaults to false. Set it to true only for an authorized HungryHub staff preview. The response is JSON:API:

{
  "data": [
    {
      "id": "61",
      "type": "add_on_packages",
      "attributes": {
        "name": "Free Birthday",
        "add_on_type": "birthday",
        "tag": "Family Birthday",
        "is_free_birthday_add_on": true,
        "item_type": "items_list",
        "menu_type": "image",
        "original_price": { "price": 0, "currency": "THB", "format": "฿0" },
        "selling_price": { "price": 0, "currency": "THB", "format": "฿0" },
        "menus": {
          "type": "image",
          "data": {
            "img": [
              {
                "id": 1,
                "birthday_item": "cake",
                "display_name": "Cake",
                "description": "Complimentary birthday cake",
                "thumb": "https://cdn.example/cake-thumb.jpg",
                "original": "https://cdn.example/cake.jpg"
              }
            ]
          }
        }
      }
    }
  ],
  "status": true,
  "message": null
}

add_on_type is the semantic category (birthday or standard). V5 tag is the humanized display label (for example, Family Birthday); the partner-portal API keeps the internal code such as family_birthday. item_type is the birthday content mode (items_list or items_image). menu_type and menus.type remain image for compatibility with the existing Pegasus image renderer. They are not birthday indicators.

Add-on detail

GET /api/v5/add_on_packages/:restaurant-add-on-id.json
  ?is_visible_for_staff=false

The detail payload uses the same data.attributes contract. A direct detail request is not filtered by the generic list visibility rule.

Availability check

POST /api/v5/restaurants/:restaurant-id/find_available_add_ons.json

Request body:

{
  "date": "2026-08-20",
  "start_time": "18:00",
  "is_visible_for_staff": false,
  "restaurant_add_on_ids": ["72", "73"]
}

Response:

{
  "success": true,
  "data": [],
  "message": null
}

The response items use the same V5 add-on serializer and therefore include the new free-birthday indicator.

Free birthday visibility rule

Pegasus must hide an item from the generic restaurant add-on catalogue when and only when:

attributes.isFreeBirthdayAddOn === true;

The shared store and SSR add-on service apply this filter before grouping cards. The field is explicit so clients do not infer birthday semantics from a zero price or from menus.type. Standard add-ons with a zero price are not hidden by this client rule.

The free birthday record may still be requested by ID for a birthday-specific flow. Hiding it from the generic catalogue does not change server-side booking validation or availability checks.

Image and item compatibility

For both items_list and items_image, V5 returns the existing image-gallery shape:

attributes.menuType === "image"
attributes.menus.type === "image"
attributes.menus.data.img[] = { thumb, original }

For items_list, menus.data.img contains the item metadata and image fields consumed by the Pegasus detail renderer. For items_image, menus.data.img contains only the normal image-gallery fields (thumb and original). There is no top-level birthday_add_on_items field in the V5 response.