Skip to Content
APIResourcesAdmin APIItems

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.

GET /api/v2/items/:id
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"
200 OK
{ "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

OptionType
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.

GET /api/v2/items/:id/items
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"
Response
204 No Content

Request Path Params IdRequestParam

OptionType
id string

Request Query Params FolderItemsRequest

OptionType
order optional
page optionalnumber
limit optionalnumber
before optionalstring
since optionalstring
ttl optionalnumber

Create Folder

POST /api/v2/items

Create a new folder under the given parent. Body: parentFolderId, name, optional fallbackName.

POST /api/v2/items
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" }'
Response
204 No Content

Request Body CreateFolderRequest

OptionType
parentFolderId string
name string
fallbackName optionalstring

Archive Items

PATCH /api/v2/items/archive

Move folder items (folders and markups) to the workspace archive. Body: folderItemIds, optional withPath (“0”|“1”).

PATCH /api/v2/items/archive
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" }'
Response
204 No Content

Request Body ArchiveFolderItemsRequest

OptionType
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”).

PATCH /api/v2/items/restore
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" }'
Response
204 No Content

Request Body ArchiveFolderItemsRequest

OptionType
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).

PATCH /api/v2/items/move
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)"} ] }'
200 OK
{ "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

OptionType
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.

PATCH /api/v2/items/:id/move
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" }'
200 OK
{ "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

OptionType
id string

Request Body MoveItemRequest

OptionType
parentFolderId string

ID of the destination parent folder. Use rootFolderId from GET /workspace to move to the workspace root. For organization-scoped API keys the destination may be in a different workspace within the same organization.

fallbackName optionalstring

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 (N) suffix.

Update Item

PATCH /api/v2/items/:id

Rename a folder or markup. Body: name. Same endpoint for both types.

PATCH /api/v2/items/:id
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" }'
Response
204 No Content

Request Path Params IdRequestParam

OptionType
id string

Request Body UpdateItemRequest

OptionType
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.

DELETE /api/v2/items/:id
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"
Response
204 No Content

Request Path Params IdRequestParam

OptionType
id string

FolderItemOrder

OptionType
FolderItemOrder `az` | `za` | `activity` | `created`

FolderWithAncestorsResponse | MarkupResponse

OptionType
FolderWithAncestorsResponse | MarkupResponse

WebpageMarkupResponse

OptionType
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

OptionType
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 mimeType already describes the source file.

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 include=images is requested. An empty array means the markup has no images yet — check isReady to tell that from a conversion still running.

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 markup_ready webhook will be sent.

VideoMarkupResponse

OptionType
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 to tell "still converting" from "no file".

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 markup_ready webhook will be sent.

PdfMarkupResponse

OptionType
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 markup_ready webhook will be sent.