Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.linkutm.com/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Tags are workspace-scoped labels you attach to links. A link can carry many tags, and a tag can be on many links - the relationship is a join table. Tag management endpoints live under /api/v1/tags. Link-level tag operations live under /api/v1/links/:linkId/tags. All endpoints require a JWT. Creating, listing, and updating tags also require the x-workspace-id header.
Authorization: Bearer <jwt>
x-workspace-id: <uuid_or_slug>
Tags are gated behind the tagsAndFolders plan feature. Creating a tag on a plan without that feature returns 403.

Create a tag

POST /api/v1/tags

Headers

HeaderRequiredNotes
Authorization: Bearer <jwt>Yes
x-workspace-id: <uuid_or_slug>YesTarget workspace
Content-Type: application/jsonYes

Body

name
string
required
Tag name. Must be unique within the workspace.
color
string
default:"#f97316"
Display color. Defaults to #f97316 if omitted.

Example request

curl -X POST https://api.linkutm.com/api/v1/tags \
  -H "Authorization: Bearer $TOKEN" \
  -H "x-workspace-id: client-globex" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "paid-social",
    "color": "#3b82f6"
  }'

Example response

{
  "id": "tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d",
  "name": "paid-social",
  "color": "#3b82f6",
  "isActive": true,
  "workspaceId": "8a7b6c5d-...",
  "createdById": "1a2b3c4d-...",
  "createdAt": "2026-05-07T10:00:00.000Z",
  "updatedAt": "2026-05-07T10:00:00.000Z",
  "_count": { "links": 0 }
}

Errors

CodeWhen
403The tagsAndFolders feature is not available on the workspace plan
409A tag with the same name already exists in the workspace

List tags

GET /api/v1/tags
Returns every tag in the workspace, each with a link count. Sorted by active first, then name ascending.

Headers

HeaderRequiredNotes
Authorization: Bearer <jwt>Yes
x-workspace-id: <uuid_or_slug>YesTarget workspace

Example request

curl https://api.linkutm.com/api/v1/tags \
  -H "Authorization: Bearer $TOKEN" \
  -H "x-workspace-id: client-globex"

Example response

[
  {
    "id": "tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d",
    "name": "paid-social",
    "color": "#3b82f6",
    "isActive": true,
    "workspaceId": "8a7b6c5d-...",
    "createdAt": "2026-05-07T10:00:00.000Z",
    "_count": { "links": 8 }
  }
]

Get a tag by ID

GET /api/v1/tags/:id
Returns one tag with its link count.

Headers

HeaderRequiredNotes
Authorization: Bearer <jwt>Yes

Example request

curl https://api.linkutm.com/api/v1/tags/tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d \
  -H "Authorization: Bearer $TOKEN"

Example response

{
  "id": "tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d",
  "name": "paid-social",
  "color": "#3b82f6",
  "isActive": true,
  "workspaceId": "8a7b6c5d-...",
  "createdAt": "2026-05-07T10:00:00.000Z",
  "updatedAt": "2026-05-07T10:00:00.000Z",
  "_count": { "links": 8 }
}

Errors

CodeWhen
404Tag not found
GET /api/v1/tags/:id/links
Returns the links carrying this tag, paginated. Links are newest first and each includes its creator and full tag set.

Headers

HeaderRequiredNotes
Authorization: Bearer <jwt>Yes

Query params

page
integer
default:"1"
Page number. Defaults to 1.
limit
integer
default:"20"
Results per page. Defaults to 20.

Example request

curl "https://api.linkutm.com/api/v1/tags/tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d/links?page=1&limit=20" \
  -H "Authorization: Bearer $TOKEN"

Example response

{
  "tag": {
    "id": "tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d",
    "name": "paid-social",
    "color": "#3b82f6",
    "_count": { "links": 8 }
  },
  "links": [
    {
      "id": "7b5d4c3e-...",
      "url": "https://example.com/q2-launch",
      "shortCode": "q2-launch",
      "title": "Q2 Launch",
      "createdAt": "2026-05-07T11:00:00.000Z",
      "createdBy": {
        "id": "1a2b3c4d-...",
        "name": "Jane",
        "email": "jane@example.com",
        "avatar": null
      },
      "tags": [
        { "tag": { "id": "tag-5f3b2a1c-...", "name": "paid-social", "color": "#3b82f6" } }
      ]
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 8,
    "pages": 1
  }
}

Errors

CodeWhen
404Tag not found

Update a tag

PATCH /api/v1/tags/:id
Updates a tag’s name or color. Both body fields are optional; send only what you want to change.

Headers

HeaderRequiredNotes
Authorization: Bearer <jwt>Yes
x-workspace-id: <uuid_or_slug>YesTarget workspace
Content-Type: application/jsonYes

Body

name
string
New tag name. A name that collides with another tag in the workspace is rejected with 409 (case-insensitive).
color
string
New display color.

Example request

curl -X PATCH https://api.linkutm.com/api/v1/tags/tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d \
  -H "Authorization: Bearer $TOKEN" \
  -H "x-workspace-id: client-globex" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "paid-social-2026",
    "color": "#22c55e"
  }'

Example response

{
  "id": "tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d",
  "name": "paid-social-2026",
  "color": "#22c55e",
  "isActive": true,
  "workspaceId": "8a7b6c5d-...",
  "updatedById": "1a2b3c4d-...",
  "updatedAt": "2026-05-07T12:00:00.000Z",
  "_count": { "links": 8 }
}

Errors

CodeWhen
404Tag not found
409A tag with the same name already exists in the workspace

Delete a tag

DELETE /api/v1/tags/:id
Deletes the tag. Its link associations are cascade deleted, so the tag is removed from every link that carried it. The links themselves are not deleted.

Headers

HeaderRequiredNotes
Authorization: Bearer <jwt>Yes

Example request

curl -X DELETE https://api.linkutm.com/api/v1/tags/tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d \
  -H "Authorization: Bearer $TOKEN"

Example response

Returns the deleted tag record.
{
  "id": "tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d",
  "name": "paid-social-2026",
  "color": "#22c55e",
  "isActive": true,
  "workspaceId": "8a7b6c5d-..."
}
Deleting a tag removes it from every link in the workspace. There is no undo.

Errors

CodeWhen
404Tag not found
POST /api/v1/tags/:id/links
Replaces the entire set of links carrying this tag. All current associations for the tag are removed, then the provided links are associated. Pass an empty array to clear the tag from every link.

Headers

HeaderRequiredNotes
Authorization: Bearer <jwt>Yes
Content-Type: application/jsonYes

Body

Array of link UUIDs that should carry this tag. An empty array removes the tag from all links.

Example request

curl -X POST https://api.linkutm.com/api/v1/tags/tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d/links \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "linkIds": ["link-uuid-1", "link-uuid-2"] }'

Example response

Returns the tag record with its refreshed link count.
{
  "id": "tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d",
  "name": "paid-social",
  "color": "#3b82f6",
  "isActive": true,
  "workspaceId": "8a7b6c5d-...",
  "_count": { "links": 2 }
}
This is a full replace. Every existing association for the tag is deleted before the new set is written. Use the per-link endpoints below to add or remove a single tag without disturbing the rest.

Errors

CodeWhen
404Tag not found
The following endpoints operate on a single link, under the path /api/v1/links/:linkId/tags. They manage which tags are attached to one link.
POST /api/v1/links/:linkId/tags/:tagId
Attaches one tag to one link. If the tag is already on the link, the existing association is returned unchanged (idempotent).

Headers

HeaderRequiredNotes
Authorization: Bearer <jwt>Yes

Example request

curl -X POST https://api.linkutm.com/api/v1/links/link-uuid-1/tags/tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d \
  -H "Authorization: Bearer $TOKEN"

Example response

{
  "linkId": "link-uuid-1",
  "tagId": "tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d",
  "createdAt": "2026-05-07T13:00:00.000Z",
  "tag": {
    "id": "tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d",
    "name": "paid-social",
    "color": "#3b82f6"
  }
}
When the tag was already on the link, the existing join record is returned without the nested tag object.

Errors

CodeWhen
404Tag not found
DELETE /api/v1/links/:linkId/tags/:tagId
Detaches one tag from one link. The tag and the link both remain - only the association is removed.

Headers

HeaderRequiredNotes
Authorization: Bearer <jwt>Yes

Example request

curl -X DELETE https://api.linkutm.com/api/v1/links/link-uuid-1/tags/tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d \
  -H "Authorization: Bearer $TOKEN"

Example response

Returns the deleted association record.
{
  "linkId": "link-uuid-1",
  "tagId": "tag-5f3b2a1c-4d6e-4a8b-9c0d-1e2f3a4b5c6d",
  "createdAt": "2026-05-07T13:00:00.000Z"
}

Errors

CodeWhen
404The tag is not associated with this link
POST /api/v1/links/:linkId/tags
Replaces the entire tag set on one link. All current tags on the link are removed, then the provided tags are attached. Pass an empty array to remove every tag from the link.

Headers

HeaderRequiredNotes
Authorization: Bearer <jwt>Yes
Content-Type: application/jsonYes

Body

tagIds
string[]
required
Array of tag UUIDs the link should carry. An empty array removes all tags from the link.

Example request

curl -X POST https://api.linkutm.com/api/v1/links/link-uuid-1/tags \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "tagIds": ["tag-uuid-1", "tag-uuid-2"] }'

Example response

Returns the link with its refreshed tag set.
{
  "id": "link-uuid-1",
  "url": "https://example.com/q2-launch",
  "shortCode": "q2-launch",
  "title": "Q2 Launch",
  "tags": [
    { "tag": { "id": "tag-uuid-1", "name": "paid-social", "color": "#3b82f6" } },
    { "tag": { "id": "tag-uuid-2", "name": "q2", "color": "#f97316" } }
  ]
}
This is a full replace. Every existing tag on the link is removed before the new set is written. Use POST /api/v1/links/:linkId/tags/:tagId to add a single tag without disturbing the rest.