API reference
The fourteen /api/page-tree/* endpoints the tree view uses, with their methods, parameters and responses.
The tree view talks to these endpoints. They are registered under Payload's API route (/api by default), and every one passes through the access gate first, so you need an authenticated user to call them. Endpoint reads and writes apply your collection access rules; URL maintenance runs with full access, as described in Access control.
rename, redirects, restore-slug, edit-url and check-segment reject unconfigured page collections with 400. Errors come back as { error: string }.
create, duplicate and status do not check whether the requested collection is configured for page-tree. They pass it to Payload, where collection access checks still apply. Do not use the configured collections list as an authorization boundary; restrict collection access and the endpoint gate.
Structure
| Method | Path | Input | What it does |
|---|---|---|---|
POST | /page-tree/move | { type, id, collection?, newParentId, newIndex, updateSlugs? } | Moves a page or folder. updateSlugs defaults to false (keep URLs). Pass the page's collection to look only there; without it every configured collection is tried. Returns 404 if the page or folder doesn't exist or the user can't read it, 404 { error: 'Folder not found' } for a missing or unreadable newParentId, and 403 if they can read the target but not update it. |
POST | /page-tree/reorder | { type, collection?, items: [{ id, sortOrder }] } | Saves the order of siblings, one at a time. Every page is checked before anything is written; 403/404 as for move. |
POST | /page-tree/create | { type, parentId, name, collection? } | Creates a folder, or a draft page in collection. The URL segment is made unique within the parent. Returns 404 { error: 'Folder not found' } if parentId doesn't exist or the user can't read it. |
DELETE | /page-tree/delete | Query: type, id, collection (required for pages), deleteChildren? | Deletes a page from that collection, or a folder. A missing or unconfigured page collection returns 400. With deleteChildren=true, a folder is deleted with everything inside it, all or nothing. |
POST | /page-tree/duplicate | Query: id, collection | Duplicates a page through Payload's duplicate operation. |
POST | /page-tree/status | { id, collection, status } | Sets _status to draft or published. |
POST | /page-tree/rename | { type, id, name, collection? } | Changes a folder's name or a page's title. Never changes a URL. 404 if the user can't read the target, 403 if they can read it but not update it. |
URLs
| Method | Path | Input | What it does |
|---|---|---|---|
POST | /page-tree/edit-url | { type, id, segment, collection? } | Changes a page's or folder's URL segment and rebuilds affected slugs. Answers 409 when the segment is already used in that location. |
GET | /page-tree/check-segment | Query: type, segment, parentId?, excludeId?, collection (pages) | Returns { available, slugifiedSegment }. Counts segments held by pages the user can't see, so it agrees with what a save will accept. Returns 404 { error: 'Folder not found' } if parentId doesn't exist or the user can't read it, and 404 { error: 'Not found' } for such an excludeId. |
GET | /page-tree/folder-impact | Query: folderId | Returns { childPageCount }: pages whose slugs a segment change would rewrite, including nested subfolders and pages the user can't see. Returns 404 { error: 'Folder not found' } if the folder doesn't exist or the user can't read it. |
POST | /page-tree/regenerate-slugs | Query: folderId? | Rebuilds slugs for every page in the folder and its subfolders. Without folderId, rebuilds every page in every configured collection. Returns { success, message, count }. |
POST | /page-tree/restore-slug | { id, collection, slug } | Restores a slug from the page's history. |
GET | /page-tree/redirects | Query: collection | Returns { redirects: [{ from, to }], count }. See Redirects. |
POST | /page-tree/migrate | — | Fills in pathSegment from the name on folders that have none, without changing page slugs. Returns { success, message, count, folders }. |
type is always 'page' or 'folder', and parentId / newParentId are null for the root.
Types
type SlugChangeReason = 'move' | 'rename' | 'regenerate' | 'restore' | 'manual' | 'edit-url'
interface SlugHistoryEntry {
slug: string // The previous slug
changedAt: Date | string // When it was replaced
reason?: SlugChangeReason
}
interface TreeNode {
id: string // Prefixed for the tree: 'folder-1' or 'page-1'
rawId?: string // Database ID without the prefix
type: 'folder' | 'page'
name: string
slug?: string
pathSegment?: string
status?: 'draft' | 'published'
children: TreeNode[]
pageCount: number
folderId?: string | null
sortOrder: number
collection?: string
slugHistory?: SlugHistoryEntry[] // Pages only
}
