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": "372c25c6-4827-4ca1-959b-5a3ea30fbb85",
"createdAt": "2026-10-23T12:00:10.824Z",
"modifiedAt": "2026-10-23T12:00:10.824Z",
"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 - 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
POST /api/v2/markups/file
Create a markup from a single file in one of supported types .
The endpoint takes a POST Content-Type: multipart/form-data request with one file field. The whole request must be under 20MB.
For larger files, and to put several images in one markup, use the upload flow and Create Markup from 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": "93a1b515-f87c-4f2c-91a4-fdfb3c042c89",
"createdAt": "2026-10-23T12:00:10.824Z",
"modifiedAt": "2026-10-23T12:00:10.824Z",
"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 - 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 from files
POST /api/v2/markups/from-files
Create a markup from files already uploaded through the upload flow.
Upload each file first (POST /uploads/upload-policy -> POST the bytes as a form to the returned presigned URL -> POST /uploads/upload-complete), then pass the resulting fileIds here.
A file there is bounded by the workspace’s remaining storage allowance rather than by a fixed per-file cap, so it is also the way to use a file too large for Create Markup from file.
Several images (png, jpeg, gif, bmp, webp, svg) become one multi-page markup, and the order of fileIds is the order they appear in.
A PDF, a video, or an image needing conversion (tiff, psd, eps) makes a markup of its own, so send exactly one fileId and do not mix it with others.
Every file must belong to this workspace and can be used only once.
curl "https://api.markup.io/api/v2/markups/from-files" \
-X POST \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"workspaceId": "123e4567-e89b-12d3-a456-426655440000",
"fileIds": ["3f1b9d2e-1c4a-4b7e-9a1d-2c5e8f0a7b31", "8c2a4e6f-5d3b-4a1c-8e9f-0b7d6c3a2e14"],
"name": "Homepage review"
}'{
"data": {
"id": "8d6f5c72-4ae8-47fb-bafb-4d17f970e71c",
"createdAt": "2026-10-23T12:00:10.824Z",
"modifiedAt": "2026-10-23T12:00:10.824Z",
"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 - MarkupResponse
Request Body CreateMarkupFromFilesRequest
| Option | Type | |
|---|---|---|
| workspaceId | string | |
| fileIds | string[] | Completed upload IDs. Each one is the |
| name optional | string | If not set, the name defaults to the first file's name without its extension. |
| parentFolderId optional | string | Folder id where the markup will be created. If not set, the workspace root folder is used. |
Search Markups
GET /api/v2/markups/search
Search markups in workspace by name or URL (includes subfolders).
Returns metadata only by default; pass include=media to attach every markup’s files, or narrow it to
include=images, videos or documents.
curl "https://api.markup.io/api/v2/markups/search?workspaceId=677e552c-f0bc-476a-9a10-ab498fb8ea94&include=media" \
-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 | |
| include optional | string | Comma-separated file payloads to expand, omitted by default because a page of markups can carry thousands of images. |
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.
limit, remaining and totalRemaining are null on an unlimited plan. used counts MarkUps charged to the plan allowance and
bundleUsed those charged to a purchased bundle, so the total created this period is used + bundleUsed.
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": 42,
"bundleUsed": 0,
"limit": 100,
"remaining": 58,
"isUnlimited": false,
"enforcementEnabled": true,
"isCustomOverride": false,
"warningThreshold": 0.8,
"isWarning": false,
"isLimitReached": false,
"bundleBalance": 0,
"totalRemaining": 58,
"isDrawingOnBundle": false,
"averageMonthlyUsage": null,
"periodStart": "2023-02-01T00:00:00.000Z",
"periodEnd": "2023-03-01T00:00:00.000Z"
}
}Get Markup
GET /api/v2/markups/:id
curl "https://api.markup.io/api/v2/markups/3a6244ea-8362-4171-b165-2fb393a8e186" \
-X GET \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" {
"data": {
"id": "c8243638-fbff-43db-ab3b-e368775f9b2d",
"createdAt": "2026-10-23T12:00:10.824Z",
"modifiedAt": "2026-10-23T12:00:10.824Z",
"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 - 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/b07c4f8f-180c-45d1-9b64-bfda1f6e866c/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",
"avatarUrl": null
}
]
}
}Response Body ProjectMessageTagsResponse
| Option | Type | |
|---|---|---|
| taggable | TaggableTagsResponse[] | |
| tagged |
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/30e94bc3-97f8-458f-b269-07a18592e770/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 |
Get Share Link
GET /api/v2/markups/:id/share-link
Returns the markup’s public share link, creating it if the markup does not have one yet.
Anyone who opens the link joins the markup as a contributor, so this is how you hand a markup to a
reviewer who has no account in the workspace.
Calling it again returns the same link rather than minting a new one, and a link that has been turned
off comes back as enabled: false with a null url until Update Share Link
turns it back on.
Creating a link requires the invite scope on the markup, which workspace- and organization-scoped API
keys hold. A caller that can view the markup but not invite on it still gets an existing link, and a
404 when there is none - it never causes one to be created.
Note that this call publishes the markup when no link exists yet, and on a plan that does not allow
private markups that cannot be undone: Update Share Link refuses to turn a link
off without that entitlement. There is currently no read-only way to ask whether a markup is already
shared - scopes on Get Markup reflects the caller’s own permissions, not the markup’s
sharing state - so treat this endpoint as a write when the entitlement is in doubt.
Organization-scoped keys must also pass workspaceId as a query param.
curl "https://api.markup.io/api/v2/markups/123e4567-e89b-12d3-a456-426655440000/share-link" \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22"{
"data": {
"inviteId": "3f1b9d2e-1c4a-4b7e-9a1d-2c5e8f0a7b31",
"enabled": true,
"url": "https://app.markup.io/invite/accept/1a2b3c4d5e6f",
"role": "project:contributor"
}
}Response Body - ShareLinkResponse
Request Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
Update Share Link
PUT /api/v2/markups/:id/share-link
Turns the markup’s public share link on or off. Turning it off makes the markup private
again and needs a plan that allows private markups; the request is rejected with a paywall error
otherwise. Turning it back on restores the same URL rather than issuing a new one.
Sending the state the link is already in succeeds and changes nothing, so a retried request is safe.
enabled: false on a markup that has never been shared is also a no-op: it reports inviteId: null
rather than creating a link in order to turn it off.
Requires the toggle-public-invite-links scope on the markup.
curl "https://api.markup.io/api/v2/markups/123e4567-e89b-12d3-a456-426655440000/share-link" \
-X PUT \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{"enabled": false}'{
"data": {
"inviteId": "3f1b9d2e-1c4a-4b7e-9a1d-2c5e8f0a7b31",
"enabled": true,
"url": "https://app.markup.io/invite/accept/1a2b3c4d5e6f",
"role": "project:contributor"
}
}Response Body - ShareLinkResponse
Request Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
Request Body UpdateShareLinkRequest
| Option | Type | |
|---|---|---|
| enabled | boolean |
|
List Markup Invites
GET /api/v2/markups/:id/invites
Lists the pending email invites on a markup - invites that have been sent but not yet
accepted. The public share link is not an email invite and is not listed here; read it from
Get Share Link.
Requires the invite scope on the markup. A caller without manage-invites sees only the invites it
sent itself.
curl "https://api.markup.io/api/v2/markups/2f518e51-4c8d-4c15-a2d2-184177ac3b5d/invites" \
-X GET \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" {
"data": {
"data": [
{
"id": "3f1b9d2e-1c4a-4b7e-9a1d-2c5e8f0a7b31",
"email": "some email",
"role": "project:contributor",
"sentAt": null,
"status": "sent"
}
]
}
}Response Body ListMarkupInvitesResponse
| Option | Type | |
|---|---|---|
| data |
Request Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
Invite to Markup
POST /api/v2/markups/:id/invites
Sends email invites to a single markup. Recipients get access to this markup only -
use this rather than Invite users, which
makes them a member of the whole workspace.
At most 25 addresses per request. The optional message appears in the invite email and requires a
plan with custom invite messages.
Free and trialing organizations cannot send markup invites; the request is rejected with a 403. A
workspace whose invites support has disabled is also rejected with a 403.
Addresses that fail individually - already has access, undeliverable domain - come back in errors
while the rest are still sent, so one bad address does not discard the batch.
curl "https://api.markup.io/api/v2/markups/123e4567-e89b-12d3-a456-426655440000/invites" \
-X POST \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"emails": ["[email protected]"],
"message": "Please review the new homepage copy."
}'{
"data": {
"successes": [
"some string"
],
"errors": [
{
"email": "some email",
"message": "some message"
}
]
}
}Response Body ISendMarkupInvitesResult
| Option | Type | |
|---|---|---|
| successes | string[] | Addresses the invite was sent to. |
| errors | Addresses that could not be invited. Empty when every address succeeded. |
Request Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
Request Body CreateMarkupInvitesRequest
| Option | Type | |
|---|---|---|
| emails | string[] | Addresses to invite, at most 25 per request. |
| message optional | string | Optional note included in the invite email. Requires a plan with custom invite messages; the request is rejected with a paywall error otherwise. |
Revoke Markup Invite
DELETE /api/v2/markups/:id/invites/:inviteId
Revokes a pending email invite on a markup. Requires the manage-invites scope, or that
the caller sent the invite itself.
Use Update Share Link to turn off the public share link - it is not revocable
here, because making a markup private has a billing rule of its own.
curl "https://api.markup.io/api/v2/markups/7d2314ed-59f6-4645-a141-d5dd091c30ec/invites/34004c18-c96b-45f6-aa61-0829da0e7917" \
-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 MarkupInviteRequestParam
| Option | Type | |
|---|---|---|
| id | string | |
| inviteId | string |
List All Markups
GET /api/v2/markups
Cursor-based pagination. Use since for next page, before for previous. Order: createdAt desc.
Returns metadata only by default; pass include=media to attach every markup’s files, or narrow it to
include=images, videos or documents. isReady is always reported, so a caller can tell a markup
still being converted from one with no files.
curl "https://api.markup.io/api/v2/markups?workspaceId=c946f0da-f0d0-40bb-a34b-7f0ede109622&include=media" \
-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 | |
| include optional | string | Comma-separated file payloads to expand, omitted by default because a page of markups can carry thousands of images. |
Update Markup
POST /api/v2/markups/:id
curl "https://api.markup.io/api/v2/markups/17716a4e-aed4-4d48-a43f-cff70adf873b" \
-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": "7424be44-9733-4ec0-a9a3-ccd62e99eafe",
"createdAt": "2026-10-23T12:00:10.824Z",
"modifiedAt": "2026-10-23T12:00:10.824Z",
"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 - 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/a5b58a23-f59f-4fef-9bbc-f54b27471043/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": "09a5b57a-e927-46fe-9619-f9316414bcff",
"createdAt": "2026-10-23T12:00:10.824Z",
"modifiedAt": "2026-10-23T12:00:10.824Z",
"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 - MarkupResponse
Request Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
Request Body UpdateMarkupReadOnlyRequest
| Option | Type | |
|---|---|---|
| readOnly | boolean |
Download Original File
GET /api/v2/markups/:id/original/download-url
Returns a short-lived presigned URL to download the markup’s retained original file.
Only available for markups created from a file whose original is still kept (see hasRetainedOriginal).
Returns 404 when no retained original exists.
curl "https://api.markup.io/api/v2/markups/a0daadb1-9abe-4fad-a7d6-49a64a84384e/original/download-url" \
-X GET \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" {
"data": {
"url": "some url",
"filename": "some filename",
"mimeType": "some mimeType",
"filesize": 123
}
}Response Body OriginalDownloadUrlResponse
| Option | Type | |
|---|---|---|
| url | string | |
| filename | string | |
| mimeType | string | |
| filesize | number |
Request Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
Keep or Archive Original File
PATCH /api/v2/markups/:id/original
Sets the per-markup original-file retention override. retainOriginal: true keeps the
original even when the workspace’s storage policy is NEVER_STORE; false archives it. An original
that has already been archived cannot be re-retained (returns 400). Returns the updated markup.
curl "https://api.markup.io/api/v2/markups/9b2f92a6-a0af-40f2-b58f-77230add6b69/original" \
-X PATCH \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" \
--data '{
"retainOriginal": true
}'{
"data": {
"id": "fb8e3ef3-a95a-44a8-83b3-4395f5eea870",
"createdAt": "2026-10-23T12:00:10.824Z",
"modifiedAt": "2026-10-23T12:00:10.824Z",
"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 - MarkupResponse
Request Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
Request Body UpdateMarkupOriginalRequest
| Option | Type | |
|---|---|---|
| retainOriginal | boolean |
Archive Original File
DELETE /api/v2/markups/:id/original
Archives the markup’s retained original file (queues it for deletion from storage) and returns the archived file size. Returns 404 when no retained original exists.
curl "https://api.markup.io/api/v2/markups/d3e0f420-eb86-45ab-aab5-841ff1dfe22c/original" \
-X DELETE \
-H "Authorization: Bearer <API-KEY-SECRET>" \
-H "Markup-API-Version: 2023-02-22" \
-H "Content-Type: application/json" {
"data": {
"archivedFileSize": 123
}
}Response Body ArchiveOriginalResponse
| Option | Type | |
|---|---|---|
| archivedFileSize | number |
Request Path Params IdRequestParam
| Option | Type | |
|---|---|---|
| id | string |
Delete Markup
DELETE /api/v2/markups/:id
curl "https://api.markup.io/api/v2/markups/4b8655c9-b633-47c6-a32f-863e5847ad60" \
-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 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": "9d933ded-50ce-4969-9cc0-784234f5bf47",
"targetFolderId": "b20bc282-351e-4b31-bdfe-e5f886ff76d8"
}'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": "84277e67-c188-49c7-b11f-c4ffa84c193c"
}'204 No ContentRequest Body BulkDeleteMarkupsRequest
| Option | Type | |
|---|---|---|
| markupIds | string[] |
Related types
ShareLinkResponse
| Option | Type | |
|---|---|---|
| inviteId | string | null | The invite that backs the link, or |
| enabled | boolean | Whether the link is live. A link that has been turned off stays off until
|
| url | string | null | The shareable URL, or |
| role | string | The role granted to whoever opens the link. Always |
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[] | |
| 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 |
TaggedUserTagResponse
| Option | Type | |
|---|---|---|
| id | string | |
| name | string | |
| string | ||
| avatarUrl | string | null |
MarkupInviteResponse
| Option | Type | |
|---|---|---|
| id | string | Invite id. Pass it to Revoke Markup Invite. |
| string | The email address the invite was sent to. | |
| role | string | The role the invite grants once accepted. Always |
| sentAt | string | null | When the invite email was sent, or |
| status | PendingInviteStatus |
|
IMarkupInviteError
| Option | Type | |
|---|---|---|
| string | The address that failed. | |
| message | string | Why it failed, e.g. the recipient already has access to the markup. |