---
title: "Get Park Map Tree"
method: GET
path: "/api/v9/parks/{park_id}/map-tree"
tags: ["parks-v9"]
---

# Get Park Map Tree

`GET /api/v9/parks/{park_id}/map-tree`

## Request

- Base URL: `https://api.alert.camp` (the document declares no server; this is the origin it was published from)
- URL: `https://api.alert.camp/api/v9/parks/{park_id}/map-tree`
- Auth: none declared

Return every non-leaf MapNode in the park's drill-down tree.

Identical handler to ``v8/parks/{id}/map-tree`` — the response shape is
provider-agnostic; re-exposed so a v9 build needs no mixed-version flow.

## Path parameters

- `park_id` string, required

## Response `200`

Successful Response

- ParkMapTreeResponse: All non-leaf MapNodes belonging to a single park.
  - `park_id` string, required
  - `nodes` MapNodeItem[], required
    - `id` string, required
    - `park_id` string, required
    - `gtc_map_id` integer, required
    - `gtc_map_type` integer, required
    - `parent_gtc_map_id` integer, nullable, required
    - `leaf_campground_id` string, nullable: Campground PK when this MapNode IS a leaf — mobile uses it to fetch the leaf's full CampgroundMaps + sites and hand off to the existing SiteMapPickerScreen with labels, long-press preview, (i) legend, etc.
    - `is_root` boolean, required: True for the entry-point node — typically the park-level map (matches Park.op_park_map_id). Mobile picker opens this one by default.
    - `image_url` string, nullable: Proxied URL for the cached PNG, served from our endpoint to bypass upstream TLS chains. Falls back to the raw upstream URL when bytes aren't cached.
    - `width` integer, required
    - `height` integer, required
    - `name_en` string, nullable
    - `name_fr` string, nullable
    - `child_links` MapNodeChildLink[]
      - `child_map_id` integer, required: GTC mapId of the child
      - `x` integer, nullable: Pixel x on the parent image
      - `y` integer, nullable: Pixel y on the parent image
      - `label_en` string, nullable
      - `label_fr` string, nullable
      - `target_kind` string, required: 'campground_map' = child is a leaf zone map already exposed via the existing /campgrounds/{id}/maps endpoint (mobile hands off to the SiteMapPicker). 'node' = child is another MapNode in the tree (mobile drills deeper).
      - `target_campground_id` string, nullable: Campground PK when target_kind='campground_map'.
    - `sites` MapNodeSiteDot[]: Site dots — populated for leaf maps that carry GTC mapResources entries. Empty on intermediate maps.
      - `site_id` string, nullable: Our Site PK. Null when the upstream marker doesn't match a Site row (typically excluded categories like group / seasonal sites that we filter at seed time but the upstream still draws on the map).
      - `label` string, nullable: Site number / name (e.g. 'B4-72', '142').
      - `x` integer, required
      - `y` integer, required
      - `is_hot` boolean
      - `has_image` boolean: True when the matching Site row has a cached photo — drives SiteMapPicker's long-press preview affordance.
    - `amenities` MapNodeAmenity[]: Amenity icon overlays — present on both leaf and non-leaf maps (intermediate maps still draw beach / visitor centre / etc. markers).
      - `legend_type` integer, required
      - `x` integer, required
      - `y` integer, required
      - `r` integer
      - `g` integer
      - `b` integer
      - `icon_asset` string: Filename under mobile/assets/legend_icons/ — empty when the upstream uses iconType=16 (badge-only, no glyph).
    - `amenity_legend` AmenityLegendEntry[]: Amenity legend key (icon + name) for providers whose icons are baked into the map artwork (Alberta) — lets the root node show the same legend as its leaf maps.
      - `label` string, required
      - `icon_url` string, required
      - `bg_color` string, nullable

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/alert/apis/alertcamp.md) · [All operations](https://skmtc.dev/alert/apis/alertcamp/llms.txt) · [OpenAPI document](https://skmtc.dev/alert/apis/alertcamp/revisions/864c8c9ef833?raw)
