Skip to content

Share Links API

Share links expose a single todo set to people outside the team through a public, unguessable URL — no Prism account required. Each link carries its own fine-grained capabilities (view, create, edit, complete, delete, comment, reorder) and an optional email allow-list. Links also power read-only badge and todo-list SVGs for embedding in READMEs and dashboards.

Share-link management endpoints require an authenticated session and the manage_set_links permission. The public endpoints under /api/shared/:token require no session — access is governed entirely by the token and the link's capabilities.


json
{
  "id": "link-uuid",
  "setId": "set-uuid",
  "setName": "Sprint 12",
  "token": "32charhextoken",
  "name": "Public roadmap",
  "canView": true,
  "canCreate": false,
  "canEdit": false,
  "canComplete": false,
  "canDelete": false,
  "canComment": false,
  "canReorder": false,
  "allowedEmails": "",
  "createdBy": "creator-user-id",
  "createdAt": "2026-06-01T10:00:00.000Z"
}
FieldTypeDescription
idstring (UUID)Internal link identifier (used for update/delete).
setIdstring (UUID)The set this link exposes.
setNamestringSet name. Only included by the team-wide listing endpoint.
tokenstringThe public, URL-safe token. Used in /api/shared/:token.
namestringHuman-readable label for the link.
canViewbooleanAllows reading the set and its todos. Defaults to true.
canCreatebooleanAllows creating todos via the public API.
canEditbooleanAllows editing todo titles.
canCompletebooleanAllows toggling completion.
canDeletebooleanAllows deleting todos.
canCommentbooleanReserved for future public commenting.
canReorderbooleanAllows reordering todos.
allowedEmailsstringComma-separated email allow-list. Empty = no restriction.
createdBystring (UUID)User who created the link.
createdAtstring (ISO 8601)Creation timestamp.

List all share links for a specific set.

Auth required: Yes — team member

Response:

json
{ "links": [ /* link objects */ ] }

List all share links across the team, each annotated with its setName. Used by the team-wide management panel.

Auth required: Yes — team member

Response:

json
{ "links": [ /* link objects, each with setName */ ] }

POST /api/teams/:teamId/sets/:setId/share-links

Create a new share link for a set. A random token is generated server-side.

Auth required: Yes — manage_set_links

Request body (all fields optional):

json
{
  "name": "Public roadmap",
  "canView": true,
  "canCreate": false,
  "canEdit": false,
  "canComplete": false,
  "canDelete": false,
  "canComment": false,
  "canReorder": false,
  "allowedEmails": "alice@example.com, bob@example.com"
}

canView defaults to true; all other capabilities default to false. allowedEmails is a comma-separated list — when non-empty, public requests must supply a matching email.

Response (201):

json
{ "link": { /* link object */ } }

Error responses:

StatuserrorCause
403"No permission to manage set links"Lacks manage_set_links.

Update a link's name, capabilities, or email allow-list. Only provided fields change.

Auth required: Yes — manage_set_links

Request body (all fields optional): same shape as create.

Response:

json
{ "ok": true }

Error responses:

StatuserrorCause
400"No updates"No recognized fields provided.
403"No permission to manage set links"Lacks manage_set_links.

Permanently delete a share link. The token immediately stops working; the underlying set and todos are unaffected.

Auth required: Yes — manage_set_links

Response:

json
{ "ok": true }

Public Endpoints

The endpoints below require no session. Authorization is derived from the token and the link's capability flags. When a link has an allowedEmails restriction, callers must pass a matching email (as a query parameter for GET/DELETE, or in the JSON body for POST/PATCH).

GET /api/shared/:token

Fetch the shared set, its todos, and the capabilities granted by the link.

Query parameters:

ParameterDescription
emailRequired only when the link has an email allow-list.

Response:

json
{
  "set": { "id": "set-uuid", "name": "Sprint 12" },
  "permissions": {
    "canView": true,
    "canCreate": false,
    "canEdit": false,
    "canComplete": false,
    "canDelete": false,
    "canComment": false,
    "canReorder": false
  },
  "requiresEmail": false,
  "todos": [
    {
      "id": "uuid",
      "userId": "creator-uuid",
      "parentId": null,
      "title": "First todo",
      "completed": false,
      "sortOrder": 1,
      "commentCount": 0,
      "assignees": [],
      "createdAt": "2026-06-01T10:00:00.000Z",
      "updatedAt": "2026-06-01T10:00:00.000Z"
    }
  ]
}

requiresEmail is true when the link is email-restricted, signalling the public page to prompt for an email before granting access.

Error responses:

StatuserrorCause
403"Access denied" (requiresEmail: true)Email restriction active and no/invalid email supplied.
404"Share link not found"Unknown token.
404"Set not found"The underlying set was deleted.

POST /api/shared/:token/todos

Create a todo through the link. Requires canCreate.

Request body:

json
{ "title": "New todo", "parentId": null, "email": "alice@example.com" }

Public-created todos are stored with the synthetic user id "shared".

Response (201): { "todo": { /* todo object */ } }

Error responses: 400 empty title; 403 "Access denied" or "This link does not allow creating todos"; 404 link or parent not found; 409 duplicate sibling title.


PATCH /api/shared/:token/todos/:id

Update a todo's title, completed, or sortOrder. Each field requires the matching capability (canEdit, canComplete, canReorder).

Request body:

json
{ "completed": true, "email": "alice@example.com" }

Response: { "ok": true }

Error responses: 400 empty title; 403 "Access denied" or a "This link does not allow ..." message for the disallowed field; 404 link or todo not found; 409 duplicate sibling title.


DELETE /api/shared/:token/todos/:id

Delete a todo. Requires canDelete.

Query parameters: email (when the link is email-restricted).

Response: { "ok": true }

Error responses: 403 "Access denied" or "This link does not allow deleting"; 404 link or todo not found.


POST /api/shared/:token/todos/reorder

Batch-update sort order. Requires canReorder.

Request body:

json
{
  "items": [
    { "id": "uuid-1", "sortOrder": 1 },
    { "id": "uuid-2", "sortOrder": 2 }
  ],
  "email": "alice@example.com"
}

Response: { "ok": true }

Error responses: 400 empty items; 403 "Access denied" or "This link does not allow reordering"; 404 link not found.


Embeddable SVGs

These endpoints render images directly (Content-Type: image/svg+xml) and are cached for 60 seconds. They are always read-only and ignore capability flags and email restrictions — anyone with the token can render them.

GET /api/shared/:token/badge.svg

A shields.io-style progress badge showing completed/total.

Query parameters:

ParameterDefaultDescription
styleflatflat or flat-square.
labelset nameLeft-hand label text.
messagedone/totalRight-hand message text.
colorauto (by progress)Right-hand background color.
labelColor#555Left-hand background color.

Returns a 404 badge ("not found") for unknown tokens or deleted sets.

GET /api/shared/:token/todo-list.svg

Renders the set's todos as a checklist image, honoring the set's split-completed ordering and sub-todo nesting.

Query parameters:

ParameterDefaultDescription
themelightlight or dark.
titleset nameHeading text (pass empty to hide).
widthautoWidth in px, clamped to 2001000.
fontSizeautoFont size in px, clamped to 1024.
maxItemsallMaximum number of rows, clamped to 1100.
showProgresstrueSet to false to hide the progress summary.
bgColorthemeBackground color override.
textColorthemeText color override.
checkColorthemeCheckbox/check color override.
borderColorthemeBorder color override.

See the Share Links guide for UI workflow and embedding examples.