Skip to Content
APIResourcesAdmin APIMarkup

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.

POST /api/v2/markups/url
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" }'
200 OK
{ "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

OptionType
url string
name optionalstring

If not set the name will be set to the URL hostname.

workspaceId optionalstring

If not set or empty, the API key's workspace is used.

parentFolderId optionalstring

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.

POST /api/v2/markups/file
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'
200 OK
{ "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

OptionType
name optionalstring

If not set the name will default based on URL or file name.

workspaceId string
parentFolderId optionalstring

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:

Using presigned S3 URL with curl
curl --upload-file /path/to/file.jpg "<presigned S3 URL>"
POST /api/v2/markups/s3
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"
200 OK
{ "data": { "url": "https://media-green-markup-io.s3.amazonaws.com/123e4567-e89b-12d3-a456-426655440000?AWSAccessKeyId=AKIAJ2...&Expires=1614787200&Signature=..." } }

Response Body S3MarkupResponse

OptionType
url string

Request Query Params CreateS3MarkupRequest

OptionType
name optionalstring

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

GET /api/v2/markups/search
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"
200 OK
{ "data": { "data": [{}] } }

Response Body ListMarkupResponse

OptionType
data T[]

Request Query Params SearchMarkupsQuery

OptionType
workspaceId string
query optionalstring
limit optionalnumber

Get Markup

GET /api/v2/markups/:id

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"
200 OK
{ "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

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

GET /api/v2/markups/:id/tag
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"
200 OK
{ "data": { "taggable": [{}], "tagged": [ { "id": "some id", "name": "some name", "email": "some email" } ] } }

Response Body ProjectMessageTagsResponse

OptionType
taggable TaggableTagsResponse[]
tagged TaggedUserTagResponse[]

Request Path Params IdRequestParam

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

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

Request Path Params IdRequestParam

OptionType
id string

List All Markups

GET /api/v2/markups

Cursor-based pagination. Use since for next page, before for previous. Order: createdAt desc.

GET /api/v2/markups
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"
200 OK
{ "data": { "data": [{}], "hasMore": true } }

Response Body ListMarkupPaginatedResponse

OptionType
data
hasMore boolean
nextCursor string
prevCursor string

Request Query Params ListMarkupsQuery

OptionType
workspaceId string
limit optionalnumber
since optionalstring
before optionalstring
ttl optionalnumber

Update Markup

POST /api/v2/markups/:id

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" }'
200 OK
{ "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

OptionType
id string

Request Body UpdateMarkupRequest

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

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

OptionType
id string

Request Body UpdateMarkupReadOnlyRequest

OptionType
readOnly boolean

Delete Markup

DELETE /api/v2/markups/:id

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"
Response
204 No Content

Request Path Params IdRequestParam

OptionType
id string

Bulk Create Markups from URLs

POST /api/v2/markups/bulk/from-url

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": [ {} ] }'
Response
204 No Content

Request Body BulkCreateMarkupsFromUrlRequest

OptionType
items BulkCreateMarkupFromUrlItem[]

Bulk Create Markups from Files

POST /api/v2/markups/bulk/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": [ {} ] }'
Response
204 No Content

Request Body BulkCreateMarkupsFromFilesRequest

OptionType
items BulkCreateMarkupFromFileItem[]

Bulk Move Markups

POST /api/v2/markups/bulk/move

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" }'
Response
204 No Content

Request Body BulkMoveMarkupsRequest

OptionType
markupIds string[]
targetFolderId string

Bulk Delete Markups

POST /api/v2/markups/bulk/delete

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" }'
Response
204 No Content

Request Body BulkDeleteMarkupsRequest

OptionType
markupIds string[]

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

TaggedUserTagResponse

OptionType
id string
name string
email string