---
title: "List a site's routes"
method: GET
path: "/api/v1/sites/{slug}/routes"
tags: ["Routes"]
---

# List a site's routes

`GET /api/v1/sites/{slug}/routes`

## Request

- Base URL: `https://api.dotsy.ai`
- URL: `https://api.dotsy.ai/api/v1/sites/{slug}/routes`
- Auth: one of:
  - HTTP bearer
  - HTTP bearer

Lists the site's routes (each maps a URL path to a content key and a layout), sorted by path, one page at a time. The default and maximum page is 1,000 routes, so most sites arrive in one response. Follow `nextCursor` until it is null, and treat `partial: true` as a window, not the whole set.

Two other row shapes are served from this same URL — `?view=pages` (pages grouped by layout) and `?purpose=redirect` (redirect rows with their issues) — and are not part of this contract.

## Path parameters

- `slug` string, required

## Query parameters

- `limit` integer
- `cursor` string
- `q` string

## Response `200`

One page of routes.

- RouteList
  - `routes` Route[], required
    - `path` string, required: The URL path. The home page is `/`. A `:param` segment makes a pattern route.
    - `contentKey` string, nullable, required: The content key this route serves. Null on a redirect, and on a route with no explicit key (it then serves the key derived from its path).
    - `layout` string, nullable, required: Layout file key, for example `layouts/main.html`.
    - `title` string, nullable, required: Page title.
    - `vars` object, nullable, required: Template variables passed to the layout.
    - `purpose` string, nullable, required: `redirect` for a redirect route, otherwise null.
    - `redirectTo` string, nullable, required: Redirect target, a root-relative path. Set only when `purpose` is `redirect`.
    - `redirectStatus` union, required: Redirect status code. Null means the default (301).
      - 301
      - 302
      - 308
    - `preserveQuery` boolean, nullable, required: Whether a redirect appends the visitor's query string to its target. Null means the default (true).
    - `navLabel` string, nullable, required: Deprecated. Menu link text — use the menu API instead.
    - `nav` object[], nullable, required: Deprecated. Menu memberships — use the menu API instead.
      - `menu` string, required: Menu this page joins — matches a <dotsy-nav menu="…"> in the layout/fragment (e.g. "primary", "footer").
      - `order` integer: Sort position among siblings in this menu, ascending. Use gaps (10, 20, 30) to leave room for inserts.
      - `parent` string, nullable: Parent route path within this menu for a nested/dropdown item (e.g. "/services"). Omit for top level.
    - `experiment` object, nullable: The page's A/B test, when it has one.
      - `id` string, required: Stable experiment slug — cookie namespace; unique per site forever.
      - `name` string, required
      - `hypothesis` string
      - `status` 'draft' | 'running' | 'ended', required
      - `variants` object[], required
        - `id` string, required: Variant arm id — default "a" / "b" on create.
        - `label` string
        - `weight` integer, required
        - `contentKey` string, required: Published body key (may be routeless).
      - `goalId` string: Optional Dotsy conversion goal; omit when tracking in external analytics.
      - `changeNote` string: One line on what the variant changes (0.56e M2). Kept here so route PATCH round-trips (weights/settings updates) don't strip it.
      - `handsOff` boolean: Hands-off mode (0.56e M4): the daily sweep may auto-promote a ≥95% winner or auto-end keep-A after 30 days. Prefer setting this via start_test; kept here so route PATCH round-trips (weights/settings updates) don't strip the flag.
      - `startedAt` string
      - `endedAt` string
    - `noindex` boolean, nullable: True when the page is excluded from the sitemap and marked `noindex`.
    - `createdBy` 'person' | 'ai' | 'key' | 'move', nullable: Who made this route a redirect: a signed-in `person`, an `ai` (MCP OAuth), an API `key`, or a page `move`. Present only on redirects.
    - `createdById` string, nullable: The user id when `createdBy` is `person`.
    - `updatedAt` number, required: Last change, Unix ms.
  - `nextCursor` string, nullable, required: Pass as `cursor` for the next page. Null on the last page.
  - `routesListTotal` integer, nullable, required: How many routes the site has (or how many match `q`). Null when the total is not known yet — never read it as zero.
  - `partial` boolean, required: True when this page is a window over a large site rather than the whole set. Keep following `nextCursor`.

## Other responses

- `400`: The `cursor` is no longer valid (`invalid_cursor`) — the site's storage changed. Restart the listing without a cursor.
- `401`: Missing or invalid credentials.
- `403`: The key or token cannot access this site (viewer role for a write, or a key scoped to other sites).
- `404`: No such site, or it is not visible to this account (`site_not_found`).

---

[API](https://skmtc.dev/dotsy/apis/dotsy-api.md) · [All operations](https://skmtc.dev/dotsy/apis/dotsy-api/llms.txt) · [OpenAPI document](https://skmtc.dev/dotsy/apis/dotsy-api/revisions/4272ed3b85d7?raw)
