Items
Unified resource for folders and markups. Same endpoints for get, list children, rename, delete. Scoped by API key workspace.
Get Item
GET /api/v2/items/:id
Get a single item by ID. Returns a folder (with ancestors) or a markup (project); response shape varies by type.
curl "https://api.markup.io/api/v2/items/88a1f01d-d213-4089-a7f7-7c37439e9d70" \
-X GET \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" {
"data": {
"id": "749cc586-33aa-4c7f-a709-a997727aa2c0",
"createdAt": "2026-09-22T11:18:38.209Z",
"modifiedAt": "2026-09-22T11:18:38.209Z",
"type": "webpage",
"name": "MarkUp.io",
"markupUrl": "https://app.markup.io/markup/f289b90a-1166-4f63-aef3-a0cce4543413",
"thumbnailUrl": "https://media.markup.io/thumbnails/markup/9b339cd0-546d-4292-a54b-6e128ce6113e",
"activeThreads": 10,
"readOnly": true,
"status": "editing",
"note": {
"id": "uuid",
"projectId": "uuid",
"note": "Internal note",
"showNoteOnProjectOpen": true
},
"projectReviews": [
{
"projectId": "uuid",
"userId": "uuid",
"comment": "Looks good",
"createdAt": 1705312800000
}
],
"scopes": [
"update-project-read-only",
"delete-project"
],
"retainOriginal": true,
"hasRetainedOriginal": true,
"url": "https://markup.io"
}
}Response Body - [FolderWithAncestorsResponse | MarkupResponse](#folderwithancestorsresponse | markupresponse)
Request Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
List Child Items
GET /api/v2/items/:id/items
List contents of a folder (folders and markups). Use GET /workspace to get archiveFolderId; then GET /items/:archiveFolderId/items to list archived items. Supports cursor-based pagination via query params: limit, since, before, ttl.
curl "https://api.markup.io/api/v2/items/fa6bf8ea-da1a-4639-a16d-195c4520cf0c/items" \
-X GET \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" 204 No ContentRequest Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
Request Query Params FolderItemsRequest
| Option | Type | |
|---|---|---|
| order optional | ||
| page optional | number | |
| limit optional | number | |
| before optional | string | |
| since optional | string | |
| ttl optional | number |
Create Folder
POST /api/v2/items
Create a new folder under the given parent. Body: parentFolderId, name, optional fallbackName.
curl "https://api.markup.io/api/v2/items" \
-X POST \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"parentFolderId": "0ce9cfb1-875c-4a82-8833-20efc29157a6",
"name": "some name"
}'204 No ContentRequest Body CreateFolderRequest
| Option | Type | |
|---|---|---|
| parentFolderId | string | |
| name | string | |
| fallbackName optional | string |
Archive Items
PATCH /api/v2/items/archive
Move folder items (folders and markups) to the workspace archive. Body: folderItemIds, optional withPath (“0”|“1”).
curl "https://api.markup.io/api/v2/items/archive" \
-X PATCH \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"folderItemIds": "bc0ec8e6-d872-4a87-b932-900e370f8d53"
}'204 No ContentRequest Body ArchiveFolderItemsRequest
| Option | Type | |
|---|---|---|
| folderItemIds | string[] |
Restore Items
PATCH /api/v2/items/restore
Restore folder items from the workspace archive to the root. Body: folderItemIds, optional withPath (“0”|“1”).
curl "https://api.markup.io/api/v2/items/restore" \
-X PATCH \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"folderItemIds": "6bcef6d2-0793-43a4-946b-2cbc749b006e"
}'204 No ContentRequest Body ArchiveFolderItemsRequest
| Option | Type | |
|---|---|---|
| folderItemIds | string[] |
Move Items (Batch)
PATCH /api/v2/items/move
Move up to 50 folder items to a single destination parent folder.
Workspace-scoped API keys can move only within their own workspace. Organization-scoped
keys may target a destination in a different workspace within the same organization —
but all source items in one request must belong to the same workspace. Batches with
sources spanning multiple workspaces are rejected with 400; split them by source
workspace and retry.
Returns 200 with { successes, errors } — inspect errors for per-item failures (e.g. cycle detection).
curl "https://api.markup.io/api/v2/items/move" \
-X PATCH \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"parentFolderId": "b1e2c3d4-5678-4abc-9012-3456789abcde",
"items": [
{"id": "d1a2b3c4-5678-4abc-9012-3456789abcde"},
{"id": "f9e8d7c6-5432-4abc-9012-3456789abcde", "fallbackName": "Q3 report (moved)"}
]
}' {
"data": {
"successes": [
{
"id": "d1a2b3c4-5678-4abc-9012-3456789abcde",
"createdAt": 1676500914137,
"modifiedAt": 1676500914137,
"deletedAt": null,
"scopes": ["folderItem:view", "folderItem:edit"],
"assignedRoleSlugs": ["project:owner"],
"name": "Q3 report",
"parentFolderId": "b1e2c3d4-5678-4abc-9012-3456789abcde",
"workspaceId": "355fe681-10d5-489e-8964-41b812d1d0fe"
}
],
"errors": [
{
"itemId": "f9e8d7c6-5432-4abc-9012-3456789abcde",
"statusCode": 422,
"message": "Cannot move a folder into its own descendant"
}
]
}
}Request Body MoveItemsBatchRequest
| Option | Type | |
|---|---|---|
| parentFolderId | string | ID of the destination parent folder. Same rules as the single-item endpoint. |
| items | MoveItemsBatchEntry[] | Items to move. Maximum 50 per request. |
Move Item
PATCH /api/v2/items/:id/move
Move a folder item to a new parent folder. Body: { parentFolderId, fallbackName? }.
Workspace-scoped API keys can move only within their own workspace. Organization-scoped keys
can move across workspaces within the same organization.
Rejects moving the workspace root, moves into a descendant of the source, and moves beyond max depth.
Returns 200 with the moved item in its new location.
curl "https://api.markup.io/api/v2/items/cdb00729-b791-4854-a782-8ecbcbde8b8c/move" \
-X PATCH \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"parentFolderId": "b1e2c3d4-5678-4abc-9012-3456789abcde",
"fallbackName": "Renamed by CRM sync"
}' {
"data": {
"id": "1ec9b6a6-49af-4ca5-9f71-e0eca57eeb0f",
"createdAt": 1676500914137,
"modifiedAt": 1676500914137,
"deletedAt": null,
"scopes": ["folderItem:view", "folderItem:edit"],
"assignedRoleSlugs": ["project:owner"],
"name": "Renamed by CRM sync",
"parentFolderId": "b1e2c3d4-5678-4abc-9012-3456789abcde",
"workspaceId": "355fe681-10d5-489e-8964-41b812d1d0fe"
}
}Request Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
Request Body MoveItemRequest
| Option | Type | |
|---|---|---|
| parentFolderId | string | ID of the destination parent folder. Use |
| fallbackName optional | string | Optional fallback name to use if a folder with the same name already exists in the destination.
When omitted, the moved folder is auto-renamed with a |
Update Item
PATCH /api/v2/items/:id
Rename a folder or markup. Body: name. Same endpoint for both types.
curl "https://api.markup.io/api/v2/items/8297440d-10f4-4e51-9d4e-ce41b20ca13e" \
-X PATCH \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"name": "some name"
}'204 No ContentRequest Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
Request Body UpdateItemRequest
| Option | Type | |
|---|---|---|
| name | string |
Delete Item
DELETE /api/v2/items/:id
Delete a folder or markup by ID. Same endpoint for both types; no need to call different APIs.
curl "https://api.markup.io/api/v2/items/d0bce32d-0421-4747-b47f-d981bb67ad45" \
-X DELETE \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" 204 No ContentRequest Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
Related types
FolderItemOrder
| Option | Type | |
|---|---|---|
| FolderItemOrder | `az` | `za` | `activity` | `created` |
FolderWithAncestorsResponse | MarkupResponse
| Option | Type | |
|---|---|---|
| FolderWithAncestorsResponse | MarkupResponse |
WebpageMarkupResponse
| Option | Type | |
|---|---|---|
| id | string | |
| createdAt | Iso8601Timestamp | |
| modifiedAt | Iso8601Timestamp | |
| deletedAt | Iso8601Timestamp | |
| type | ProjectType | |
| name | string | |
| markupUrl | string | |
| thumbnailUrl | string | |
| activeThreads | number | |
| readOnly | boolean | |
| status | ProjectStatus | |
| note | ProjectNoteResponse | |
| projectReviews | ProjectReviewResponse[] | |
| scopes | string[] | |
| retainOriginal | boolean | |
| hasRetainedOriginal | boolean | |
| url | string |
ImageMarkupResponse
| Option | Type | |
|---|---|---|
| id | string | |
| createdAt | Iso8601Timestamp | |
| modifiedAt | Iso8601Timestamp | |
| deletedAt | Iso8601Timestamp | |
| type | ProjectType | |
| name | string | |
| markupUrl | string | |
| thumbnailUrl | string | |
| activeThreads | number | |
| readOnly | boolean | |
| status | ProjectStatus | |
| note | ProjectNoteResponse | |
| projectReviews | ProjectReviewResponse[] | |
| scopes | string[] | |
| retainOriginal | boolean | |
| hasRetainedOriginal | boolean | |
| originalMimeType | string | Mime type of the file the markup was created from, when it differs from the images
themselves (a converted document, for example). Absent for markups built directly from uploaded
images, where the per-image |
| images | MarkupImage[] | The images that make up this markup, in display order. Always present on a single-markup
read; on the list and search endpoints only when |
| isReady | boolean | Some of the files need to be converted before Markup is ready for reviewing.
After the conversion is done, this flag will be set to true and the |
VideoMarkupResponse
| Option | Type | |
|---|---|---|
| id | string | |
| createdAt | Iso8601Timestamp | |
| modifiedAt | Iso8601Timestamp | |
| deletedAt | Iso8601Timestamp | |
| type | ProjectType | |
| name | string | |
| markupUrl | string | |
| thumbnailUrl | string | |
| activeThreads | number | |
| readOnly | boolean | |
| status | ProjectStatus | |
| note | ProjectNoteResponse | |
| projectReviews | ProjectReviewResponse[] | |
| scopes | string[] | |
| retainOriginal | boolean | |
| hasRetainedOriginal | boolean | |
| video | MarkupVideo | The video this markup was created from. Absent until the conversion job has produced it —
check |
| isReady | boolean | Some of the files need to be converted before Markup is ready for reviewing.
After the conversion is done, this flag will be set to true and the |
PdfMarkupResponse
| Option | Type | |
|---|---|---|
| id | string | |
| createdAt | Iso8601Timestamp | |
| modifiedAt | Iso8601Timestamp | |
| deletedAt | Iso8601Timestamp | |
| type | ProjectType | |
| name | string | |
| markupUrl | string | |
| thumbnailUrl | string | |
| activeThreads | number | |
| readOnly | boolean | |
| status | ProjectStatus | |
| note | ProjectNoteResponse | |
| projectReviews | ProjectReviewResponse[] | |
| scopes | string[] | |
| retainOriginal | boolean | |
| hasRetainedOriginal | boolean | |
| document | MarkupDocument | The document this markup was created from. Absent while the upload is still being processed, so a client must not assume it is present. |
| isReady | boolean | Some of the files need to be converted before Markup is ready for reviewing.
After the conversion is done, this flag will be set to true and the |