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": "c3ed2198-7646-4266-a2ab-92a8f02cf432",
"createdAt": "2026-07-23T17:45:55.655Z",
"modifiedAt": "2026-07-23T17:45:55.655Z",
"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": "03ea79b8-3fda-4344-88f7-034bcf05f076",
"createdAt": "2026-07-23T17:45:55.655Z",
"modifiedAt": "2026-07-23T17:45:55.655Z",
"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=8319b3d9-c2b5-4d78-a20c-23d272a8b097&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=7a4edd62-21aa-47c0-9eb5-7b6575f8677a" \
-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 Usage
GET /api/v2/markups/usage
Returns the workspace’s monthly MarkUp usage: scope, allowance, used, remaining, reset date and warning/limit flags.
curl "https://api.markup.io/api/v2/markups/usage" \
-X GET \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" {
"data": {
"scope": "Workspace",
"used": 123,
"isUnlimited": true,
"enforcementEnabled": true,
"isCustomOverride": true,
"warningThreshold": 123,
"isWarning": true,
"isLimitReached": true,
"periodStart": "some periodStart",
"periodEnd": "some periodEnd",
"organization": {},
"workspaces": {}
}
}Response Body MarkupUsageResponse
| Option | Type | |
|---|---|---|
| scope | ||
| used | number | |
| isUnlimited | boolean | |
| enforcementEnabled | boolean | |
| isCustomOverride | boolean | |
| warningThreshold | number | |
| isWarning | boolean | |
| isLimitReached | boolean | |
| periodStart | string | |
| periodEnd | string | |
| scope | ||
| organization | MarkupUsageResponse | |
| workspaces | Array |
Get Markup
GET /api/v2/markups/:id
curl "https://api.markup.io/api/v2/markups/561b18d8-5bd0-4656-b3ad-50ed63ceefbd" \
-X GET \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" {
"data": {
"id": "ba81c8bd-f79e-47ed-8683-7789a49e4c43",
"createdAt": "2026-07-23T17:45:55.656Z",
"modifiedAt": "2026-07-23T17:45:55.656Z",
"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/6cf2415a-9069-45ee-a0fe-b6d517b526af/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/19aadd0a-3f03-49a4-b351-2c0dbd2b2afe/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=07a196aa-18e8-4205-a840-9b12fad16fb7" \
-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/1f6e9910-5044-4013-b031-5b7febf2dd65" \
-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": "279f76ec-f5c3-47ec-adaa-37be58df6bc9",
"createdAt": "2026-07-23T17:45:55.656Z",
"modifiedAt": "2026-07-23T17:45:55.656Z",
"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/51da0c12-5073-4266-827f-8cfb8a2ebebd/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": "9862cefc-1c39-4a2d-b6fa-d801ea6a3ed0",
"createdAt": "2026-07-23T17:45:55.656Z",
"modifiedAt": "2026-07-23T17:45:55.656Z",
"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/4ae5543c-9214-4b8a-9579-0263f34f0e2d" \
-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": "453eb9b0-8f85-41bb-ade4-5489165d2273",
"targetFolderId": "ca51bf41-8f2e-47db-bff6-8660f072116a"
}'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": "4dccc0c3-3c0f-4136-bc00-20d2a0102aaa"
}'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 |
MarkupLimitScope
| Option | Type | |
|---|---|---|
| MarkupLimitScope | `Workspace` | `Organization` |
TaggedUserTagResponse
| Option | Type | |
|---|---|---|
| id | string | |
| name | string | |
| string |