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.