Markup
Markup is the main resource of the MarkUp.io API. Create, get, update, and delete markups (MarkUp projects); list and search by workspace; bulk create, move, and delete.
Create Markup from URL
POST /api/v2/markups/url
This URL should lead to webpage or one of supported types .
curl "https://api.markup.io/api/v2/markups/url" \
-X POST \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"url": "https://markup.io",
"name": "My Markup"
}'{
"data": {
"id": "9a476d0d-d689-42eb-bc3f-c7ba45d154d0",
"createdAt": "2026-06-09T07:17:45.221Z",
"modifiedAt": "2026-06-09T07:17:45.221Z",
"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"],
"url": "https://markup.io"
}
}Response Body - MarkupResponse
Request Body CreateUrlMarkupRequest
| Option | Type | |
|---|---|---|
| url | string | |
| name optional | string | If not set the name will be set to the URL hostname. |
| workspaceId optional | string | If not set or empty, the API key's workspace is used. |
| parentFolderId optional | string | Folder id where the markup will be created. If not set, the workspace root folder is used. |
Create Markup from file(s)
POST /api/v2/markups/file
Create a markup from a file or files in one of supported types .
The endpoint can be used by POST Content-Type: multipart/form-data request with file or files fields. This doesn’t allow uploading files larger than 100MB.
See Create Markup via S3 upload for uploading larger files.
curl "https://api.markup.io/api/v2/markups/file?workspaceId=123e4567-e89b-12d3-a456-426655440000" \
-X POST \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: multipart/form-data" \
-F 'file=@/path/to/pictures/picture.jpg'{
"data": {
"id": "6367eeda-72fc-43e3-9089-6a2f6900e5dd",
"createdAt": "2026-06-09T07:17:45.221Z",
"modifiedAt": "2026-06-09T07:17:45.221Z",
"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"],
"url": "https://markup.io"
}
}Response Body - MarkupResponse
Request Query Params CreateFileMarkupRequest
| Option | Type | |
|---|---|---|
| name optional | string | If not set the name will default based on URL or file name. |
| workspaceId | string | |
| parentFolderId optional | string | Folder id where the markup will be created. If not set, the workspace root folder is used. |
Create Markup via S3 upload
POST /api/v2/markups/s3
Create a markup from a file in one of supported types . This endpoint allows uploading files larger than 100MB. The endpoint replies with a presigned S3 URL to which the file should be uploaded. Example of uploading a file to S3 using presigned URL:
curl --upload-file /path/to/file.jpg "<presigned S3 URL>"curl "https://api.markup.io/api/v2/markups/s3?name=My+Markup&workspaceId=82677b4f-32ab-45ae-8343-4ed21edc6b46&filesize=123&mimeType=some+mimeType" \
-X POST \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json"{
"data": {
"url": "https://media-green-markup-io.s3.amazonaws.com/123e4567-e89b-12d3-a456-426655440000?AWSAccessKeyId=AKIAJ2...&Expires=1614787200&Signature=..."
}
}Response Body S3MarkupResponse
| Option | Type | |
|---|---|---|
| url | string |
Request Query Params CreateS3MarkupRequest
| Option | Type | |
|---|---|---|
| name optional | string | If not set the name will default based on URL or file name. |
| workspaceId | string | |
| filesize | number | |
| mimeType | string |
Search Markups
GET /api/v2/markups/search
Search markups in workspace by name or URL (includes subfolders).
curl "https://api.markup.io/api/v2/markups/search?workspaceId=aaafc8a4-2ae4-464e-bd3e-9f33d3a94042" \
-X GET \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json"{
"data": {
"data": [{}]
}
}Response Body ListMarkupResponse
| Option | Type | |
|---|---|---|
| data | T[] |
Request Query Params SearchMarkupsQuery
| Option | Type | |
|---|---|---|
| workspaceId | string | |
| query optional | string | |
| limit optional | number |
Get Markup
GET /api/v2/markups/:id
curl "https://api.markup.io/api/v2/markups/bf428df7-6fa6-44c1-bda8-e9754682df33" \
-X GET \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json"{
"data": {
"id": "eb4db70b-8ce1-460f-b685-e52687b6717b",
"createdAt": "2026-06-09T07:17:45.221Z",
"modifiedAt": "2026-06-09T07:17:45.221Z",
"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"],
"url": "https://markup.io"
}
}Response Body - MarkupResponse
Request Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
Get Markup Tag
GET /api/v2/markups/:id/tag
Returns taggable and tagged users for the markup (project). Same as v1 GET tag/project/:id.
curl "https://api.markup.io/api/v2/markups/a47297fa-7858-4675-a7b0-b50de3d42470/tag" \
-X GET \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json"{
"data": {
"taggable": [{}],
"tagged": [
{
"id": "some id",
"name": "some name",
"email": "some email"
}
]
}
}Response Body ProjectMessageTagsResponse
| Option | Type | |
|---|---|---|
| taggable | TaggableTagsResponse[] | |
| tagged | TaggedUserTagResponse[] |
Request Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
List Markup View Modes
GET /api/v2/markups/:id/view-modes
Returns the available view modes (device breakpoints) for a markup, with per-mode thread counts.
curl "https://api.markup.io/api/v2/markups/3ef4c37b-8d69-422d-afd2-60f5415e6049/view-modes" \
-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 |
List All Markups
GET /api/v2/markups
Cursor-based pagination. Use since for next page, before for previous. Order: createdAt desc.
curl "https://api.markup.io/api/v2/markups?workspaceId=27fa8c2c-1fb5-4700-a923-37d502499f99" \
-X GET \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json"{
"data": {
"data": [{}],
"hasMore": true
}
}Response Body ListMarkupPaginatedResponse
| Option | Type | |
|---|---|---|
| data | ||
| hasMore | boolean | |
| nextCursor | string | |
| prevCursor | string |
Request Query Params ListMarkupsQuery
| Option | Type | |
|---|---|---|
| workspaceId | string | |
| limit optional | number | |
| since optional | string | |
| before optional | string | |
| ttl optional | number |
Update Markup
POST /api/v2/markups/:id
curl "https://api.markup.io/api/v2/markups/ced1e6bf-3bc5-4e33-b05f-bae57b371518" \
-X POST \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"name": "MarkUp.io"
}'{
"data": {
"id": "cb57dfea-f87f-43da-906c-cce4ac544f62",
"createdAt": "2026-06-09T07:17:45.221Z",
"modifiedAt": "2026-06-09T07:17:45.221Z",
"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"],
"url": "https://markup.io"
}
}Response Body - MarkupResponse
Request Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
Request Body UpdateMarkupRequest
| Option | Type | |
|---|---|---|
| name | string |
Pause or Resume New Comments
PATCH /api/v2/markups/:id/read-only
Pauses or resumes new comments on the markup by toggling its readOnly state.
Pausing requires a plan with pauseCommentsEnabled; resuming is always allowed.
curl "https://api.markup.io/api/v2/markups/5b3085ec-2df2-4ec3-968c-f695acaad4e4/read-only" \
-X PATCH \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"readOnly": true
}'{
"data": {
"id": "8989f070-b20f-468f-9504-13a9a1e5e843",
"createdAt": "2026-06-09T07:17:45.221Z",
"modifiedAt": "2026-06-09T07:17:45.221Z",
"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"],
"url": "https://markup.io"
}
}Response Body - MarkupResponse
Request Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
Request Body UpdateMarkupReadOnlyRequest
| Option | Type | |
|---|---|---|
| readOnly | boolean |
Delete Markup
DELETE /api/v2/markups/:id
curl "https://api.markup.io/api/v2/markups/aeba5080-7bc6-4dc9-b868-767fd3263c5c" \
-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 |
Bulk Create Markups from URLs
POST /api/v2/markups/bulk/from-url
curl "https://api.markup.io/api/v2/markups/bulk/from-url" \
-X POST \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"items": [
{}
]
}'204 No ContentRequest Body BulkCreateMarkupsFromUrlRequest
| Option | Type | |
|---|---|---|
| items | BulkCreateMarkupFromUrlItem[] |
Bulk Create Markups from Files
POST /api/v2/markups/bulk/from-files
curl "https://api.markup.io/api/v2/markups/bulk/from-files" \
-X POST \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"items": [
{}
]
}'204 No ContentRequest Body BulkCreateMarkupsFromFilesRequest
| Option | Type | |
|---|---|---|
| items | BulkCreateMarkupFromFileItem[] |
Bulk Move Markups
POST /api/v2/markups/bulk/move
curl "https://api.markup.io/api/v2/markups/bulk/move" \
-X POST \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"markupIds": "71031c80-c87f-4de1-b443-b9d81c237bb3",
"targetFolderId": "617e2eb7-12a9-46ff-bc8c-ca6b45b41e72"
}'204 No ContentRequest Body BulkMoveMarkupsRequest
| Option | Type | |
|---|---|---|
| markupIds | string[] | |
| targetFolderId | string |
Bulk Delete Markups
POST /api/v2/markups/bulk/delete
curl "https://api.markup.io/api/v2/markups/bulk/delete" \
-X POST \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"markupIds": "267e7e5a-84ca-4ba1-b66b-c6e1913a5e4a"
}'204 No ContentRequest Body BulkDeleteMarkupsRequest
| Option | Type | |
|---|---|---|
| markupIds | string[] |
Related types
MarkupResponse
| Option | Type | |
|---|---|---|
| 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[] | |
| 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[] | |
| originalMimeType | string | |
| images | MarkupImage[] | |
| 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[] | |
| video | MarkupVideo | |
| 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 |
TaggedUserTagResponse
| Option | Type | |
|---|---|---|
| id | string | |
| name | string | |
| string |