Skip to Content
Pins APIPin Types & Schemas

Pin Types & Schemas

Every pin uses pin_type + pin_config. The API validates pin_config against the schema for that type. Invalid payloads return 400 with code PIN_CONFIG_INVALID.

{ "pin_type": "<type-id>", "pin_config": { /* shape depends on type — see below */ }, "metadata": { "title": "Required title" } }

TypeScript types are exported from @pindownai/client-js (e.g. MarkdownPinConfig, StatCardsPinConfig, PinConfigByType).

The product ships 43 pin_type values. Sections below group them by use case.

Legend: required fields must be present. All other documented fields are optional unless marked required in a nested object.


Content & text

markdown

Rich text content. Server enables Yjs collaboration when content is provided.

FieldTypeRequiredDescription
contentstringNoMarkdown body
collaboration.enabledbooleanNoSet automatically by the server when seeding content
{ "pin_type": "markdown", "pin_config": { "content": "# Weekly report\n\n- Revenue up 18%\n- 3 new customers" }, "metadata": { "title": "Weekly report" } }

text-media

Text block alongside an image or embed. Set mediaType to "image" or "embed", then provide the matching config object.

FieldTypeRequiredDescription
titlestringNoMain headline
textstringNoBody copy
subtextstringNoSecondary paragraph
textPositionstringNo"left" or "right" — text side relative to media
mediaTypestringNo"image" or "embed"
imageConfig.urlstringNo*Image URL (when mediaType is "image")
imageConfig.altstringNoImage alt text
imageConfig.fileIdstringNoReference to an uploaded file
embedConfig.typestringNo*e.g. "youtube", "loom", "figma"
embedConfig.urlstringNo*Embed URL (when mediaType is "embed")
embedConfig.aspectRatiostringNoe.g. "16:9", "4:3"

* Provide imageConfig when using an image, or embedConfig when using an embed.

Image example:

{ "pin_type": "text-media", "pin_config": { "title": "Product launch", "text": "Summary of the Q1 launch initiative.", "subtext": "Shipped to all workspace customers.", "textPosition": "left", "mediaType": "image", "imageConfig": { "url": "https://example.com/hero-screenshot.png", "alt": "Dashboard screenshot" } }, "metadata": { "title": "Launch hero" } }

Embed example:

{ "pin_type": "text-media", "pin_config": { "title": "Product demo", "text": "Watch the 2-minute walkthrough.", "textPosition": "right", "mediaType": "embed", "embedConfig": { "type": "youtube", "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "aspectRatio": "16:9" } }, "metadata": { "title": "Demo video" } }

intro

Section intro / heading block.

FieldTypeRequiredDescription
headingstringYesMain heading
subheadingstringNoSecondary line
{ "pin_type": "intro", "pin_config": { "heading": "Project overview", "subheading": "Q1 initiative" }, "metadata": { "title": "Intro" } }

image

Single image display.

FieldTypeRequiredDescription
urlstringNoImage URL
altTextstringNoAlt text
fitstringNo"cover", "contain", etc.
{ "pin_type": "image", "pin_config": { "url": "https://example.com/photo.png", "altText": "Dashboard screenshot", "fit": "cover" }, "metadata": { "title": "Screenshot" } }

Grid of images.

FieldTypeRequiredDescription
imagesarrayNoList of image objects
images[].urlstringNoImage URL
images[].altstringNoAlt text
images[].fileIdstringNoReference to an uploaded file
{ "pin_type": "gallery", "pin_config": { "images": [ { "url": "https://example.com/a.png", "alt": "Slide A" }, { "url": "https://example.com/b.png", "alt": "Slide B" } ] }, "metadata": { "title": "Photo gallery" } }

video

Uploaded or hosted MP4 video player.

FieldTypeRequiredDescription
urlstringNoVideo file URL
fileIdstringNoReference to an uploaded file
fileNamestringNoDisplay filename
mimeTypestringNo"video/mp4" (only supported type)
captionstringNoCaption below the player
sizenumberNoFile size in bytes
{ "pin_type": "video", "pin_config": { "url": "https://example.com/demo.mp4", "fileName": "demo.mp4", "mimeType": "video/mp4", "caption": "Product walkthrough" }, "metadata": { "title": "Demo video" } }

audio

Audio player (single track or multi-track playlist). Requires url or at least one entry in tracks.

FieldTypeRequiredDescription
urlstringNo*Primary audio URL
fileIdstringNoReference to an uploaded file
fileNamestringNoDisplay filename
mimeTypestringNo"audio/mpeg", "audio/wav", or "audio/x-wav"
captionstringNoCaption below the player
sizenumberNoFile size in bytes
tracksarrayNo*Up to 10 tracks (playlist mode)
tracks[].urlstringYesTrack URL
tracks[].fileNamestringNoTrack label

* Provide url for a single track, or tracks with at least one item.

{ "pin_type": "audio", "pin_config": { "url": "https://example.com/podcast.mp3", "fileName": "podcast.mp3", "mimeType": "audio/mpeg", "caption": "Episode 12" }, "metadata": { "title": "Podcast clip" } }

business-card

CV-style contact section with key–value fields and optional photo.

FieldTypeRequiredDescription
sectionTitlestringNoSection heading
fieldsarrayYes (min 1)Key–value rows
fields[].idstringYesField id
fields[].keystringYesLabel (e.g. "E-Mail")
fields[].valuestringYesValue
imageConfig.urlstringNoPhoto URL
imageConfig.altstringNoPhoto alt text
imageConfig.fileIdstringNoReference to an uploaded file
imagePositionstringNo"left" or "right"
{ "pin_type": "business-card", "pin_config": { "sectionTitle": "Contact", "fields": [ { "id": "f1", "key": "Name", "value": "Jane Doe" }, { "id": "f2", "key": "E-Mail", "value": "jane@example.com" } ], "imageConfig": { "url": "https://example.com/photo.jpg", "alt": "Jane Doe" }, "imagePosition": "right" }, "metadata": { "title": "Team contact" } }

notes

Quick-capture note memory (title + optional body per note).

FieldTypeRequiredDescription
notesarrayNoNote entries
notes[].idstringNoNote id
notes[].titlestringYesNote title
notes[].contentstringNoNote body
notes[].ordernumberNoSort order
{ "pin_type": "notes", "pin_config": { "notes": [ { "id": "n1", "title": "Meeting takeaway", "content": "Ship API v1 by Friday.", "order": 0 }, { "id": "n2", "title": "Follow-up", "content": "Schedule design review.", "order": 1 } ] }, "metadata": { "title": "Scratchpad" } }

Data & metrics

stat-cards

KPI cards with optional trend indicators.

FieldTypeRequiredDescription
cardsarrayYes (min 1)Stat card list
cards[].titlestringYesMetric label
cards[].valuestring | numberYesMetric value
cards[].changestringNoChange label, e.g. "+18.2%"
cards[].trendstringNo"up", "down", "neutral"
cards[].iconstringNoIcon identifier
{ "pin_type": "stat-cards", "pin_config": { "cards": [ { "title": "Revenue", "value": "$125,430", "change": "+18.2%", "trend": "up" }, { "title": "Users", "value": 1234, "change": "+5%", "trend": "up" } ] }, "pin_layout": "2x1", "metadata": { "title": "KPI dashboard" } }

charts

Data visualizations (line, bar, pie, area, radar, etc.).

FieldTypeRequiredDescription
chartTypestringNoe.g. "line", "bar", "pie", "area", "radar"
titlestringNoChart title
dataarrayNoData points (objects with arbitrary keys)
xAxisstringNoKey used for X axis
yAxisstringNoKey used for Y axis
dataKeysstring[]NoSeries keys to plot
{ "pin_type": "charts", "pin_config": { "chartType": "line", "title": "API calls", "xAxis": "name", "yAxis": "value", "dataKeys": ["value"], "data": [ { "name": "Mon", "value": 1200 }, { "name": "Tue", "value": 1450 }, { "name": "Wed", "value": 1680 } ] }, "pin_layout": "2x2", "metadata": { "title": "API traffic" } }

table

Tabular data with typed columns.

FieldTypeRequiredDescription
columnsarrayYes (min 1)Column definitions
columns[].idstringYesColumn key (used in row cells)
columns[].namestringYesColumn header label
columns[].typestringNoe.g. "text", "number", "date"
rowsarrayNoRow objects
rows[].idstringNoRow identifier
rows[].cellsobjectNo{ [columnId]: value }
{ "pin_type": "table", "pin_config": { "columns": [ { "id": "product", "name": "Product", "type": "text" }, { "id": "sales", "name": "Sales", "type": "number" } ], "rows": [ { "id": "r1", "cells": { "product": "Widget A", "sales": 1250 } }, { "id": "r2", "cells": { "product": "Widget B", "sales": 890 } } ] }, "pin_layout": "2x2", "metadata": { "title": "Sales table" } }

json-viewer

Pretty-printed JSON object.

FieldTypeRequiredDescription
jsonanyNoParsed JSON value
jsonStringstringNoJSON as string (alternative to json)
titlestringNoViewer title
{ "pin_type": "json-viewer", "pin_config": { "json": { "status": "ok", "count": 42 }, "jsonString": "{\"status\":\"ok\",\"count\":42}", "title": "API response" }, "metadata": { "title": "Payload viewer" } }

json-list

JSON array viewer.

FieldTypeRequiredDescription
jsonarrayNoParsed JSON array
jsonStringstringNoJSON array as string
{ "pin_type": "json-list", "pin_config": { "json": [{ "id": 1, "name": "Alpha" }, { "id": 2, "name": "Beta" }], "jsonString": "[{\"id\":1,\"name\":\"Alpha\"}]" }, "metadata": { "title": "Records list" } }

csv-viewer

CSV data rendered as a table.

FieldTypeRequiredDescription
csvTextstringNoRaw CSV text
csvDataarrayNoParsed rows as objects
fileNamestringNoDisplay name
{ "pin_type": "csv-viewer", "pin_config": { "csvText": "name,value\nalpha,1\nbeta,2", "csvData": [ { "name": "alpha", "value": 1 }, { "name": "beta", "value": 2 } ], "fileName": "export.csv" }, "metadata": { "title": "CSV export" } }

qr-code

QR code for a URL with optional label.

FieldTypeRequiredDescription
urlstringNoTarget URL encoded in the QR code
labelstringNoLabel shown below the code
{ "pin_type": "qr-code", "pin_config": { "url": "https://pindown.ai", "label": "Visit Pindown" }, "metadata": { "title": "QR — Website" } }

social-handles

Social profile links with platform icons.

FieldTypeRequiredDescription
titlestringNoSection title
showLabelsbooleanNoShow platform labels
iconSizenumberNoIcon size in pixels
handlesarrayNoSocial entries
handles[].platformstringYesPlatform id (e.g. "x", "linkedin")
handles[].urlstringYesProfile URL
handles[].labelstringNoDisplay label
{ "pin_type": "social-handles", "pin_config": { "title": "Follow us", "showLabels": true, "handles": [ { "platform": "x", "url": "https://x.com/pindownai", "label": "@pindownai" }, { "platform": "linkedin", "url": "https://linkedin.com/company/pindown", "label": "Pindown" } ] }, "metadata": { "title": "Social links" } }

Files & embeds

embed

Embedded video or external content.

FieldTypeRequiredDescription
urlstringNoEmbed URL
typestringNoe.g. "youtube", "vimeo", "loom"
{ "pin_type": "embed", "pin_config": { "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "type": "youtube" }, "metadata": { "title": "Demo video" } }

pdf-viewer

Inline PDF viewer.

FieldTypeRequiredDescription
pdf.urlstringYesPDF file URL
pdf.fileNamestringNoDisplay filename
pdf.titlestringNoDocument title
{ "pin_type": "pdf-viewer", "pin_config": { "pdf": { "url": "https://example.com/report.pdf", "fileName": "report.pdf", "title": "Q4 Report" } }, "metadata": { "title": "PDF report" } }

excel-viewer

Inline Excel spreadsheet viewer.

FieldTypeRequiredDescription
excel.urlstringYesSpreadsheet URL
excel.fileNamestringNoDisplay filename
excel.titlestringNoDocument title
{ "pin_type": "excel-viewer", "pin_config": { "excel": { "url": "https://example.com/data.xlsx", "fileName": "data.xlsx", "title": "Sales data" } }, "metadata": { "title": "Spreadsheet" } }

file-upload

List of uploaded files.

FieldTypeRequiredDescription
filesarrayNoFile metadata objects
displayModestringNoe.g. "list", "grid"
{ "pin_type": "file-upload", "pin_config": { "files": [], "displayMode": "list" }, "metadata": { "title": "Attachments" } }

Diagrams & planning

mermaid

Mermaid diagram (flowchart, sequence, gantt, etc.). Requires code or diagram.

FieldTypeRequiredDescription
codestringYesÂąMermaid source
diagramstringYesÂąAlternative to code
titlestringNoDiagram title

Âą At least one of code or diagram must be non-empty.

{ "pin_type": "mermaid", "pin_config": { "code": "graph TD\n A[Start] --> B{Decision}\n B -->|Yes| C[Done]\n B -->|No| D[Retry]", "title": "Flow" }, "metadata": { "title": "Architecture diagram" } }

trace

Agent or workflow execution trace with timed spans.

FieldTypeRequiredDescription
titlestringNoTrace title
livebooleanNoLive-updating trace
spansarrayYes (min 1)Execution spans
spans[].namestringYesSpan name
spans[].statusstringYes"completed", "running", "pending", or "failed"
spans[].typestringNo"system", "agent", or "tool"
spans[].timestampstringNoTimestamp label
spans[].durationstringNoDuration label
spans[].detailsstringNoExtra detail text
{ "pin_type": "trace", "pin_config": { "title": "Workflow run", "live": false, "spans": [ { "id": "1", "type": "system", "name": "Initialization", "status": "completed", "timestamp": "10:42:01.005", "duration": "12ms", "details": "Initialized context" }, { "id": "2", "type": "tool", "name": "workspace_query", "status": "completed", "timestamp": "10:42:01.468", "duration": "1.2s", "details": "Searching workspace" } ] }, "metadata": { "title": "Agent trace" } }

timeline

Chronological timeline.

FieldTypeRequiredDescription
modestringNoe.g. "alternating", "left", "right"
itemsarrayNoTimeline entries
items[].titlestringNoDate or label
items[].cardTitlestringNoEvent title
items[].cardDetailedTextstringNoEvent description
{ "pin_type": "timeline", "pin_config": { "mode": "alternating", "items": [ { "title": "2024-01-01", "cardTitle": "Launch", "cardDetailedText": "Shipped v1 to production" }, { "title": "2024-06-01", "cardTitle": "Series A", "cardDetailedText": "Closed funding round" } ] }, "metadata": { "title": "Company timeline" } }

steps

Numbered step-by-step process.

FieldTypeRequiredDescription
stepsarrayYes (min 1)Step list
steps[].titlestringYesStep title
steps[].descriptionstringNoStep details
{ "pin_type": "steps", "pin_config": { "steps": [ { "title": "Install SDK", "description": "npm install @pindownai/client-js" }, { "title": "Create API key", "description": "Workspace plan → Settings → API" }, { "title": "Push first pin", "description": "POST /v1/pins" } ] }, "metadata": { "title": "Getting started" } }

plan

Phased implementation plan with tasks and rich content blocks.

FieldTypeRequiredDescription
titlestringNoPlan title
statusstringNo"draft", "in-progress", or "completed"
breadcrumbsarrayNoContext breadcrumbs ({ label })
phasesarrayYes (min 1)Plan phases
phases[].titlestringYesPhase title
phases[].statusstringNoPhase status
phases[].tasksarrayYes (min 1)Tasks in the phase
phases[].tasks[].titlestringYesTask title
phases[].tasks[].blocksarrayNoContent blocks (details, command, code, text, link, mermaid, summary)
{ "pin_type": "plan", "pin_config": { "title": "Implementation Plan", "status": "in-progress", "phases": [ { "id": "p1", "title": "Phase 1: Setup", "status": "in-progress", "tasks": [ { "id": "t1", "number": "1.1", "title": "Install dependencies", "blocks": [{ "type": "command", "command": "npm install @pindownai/client-js" }] } ] } ] }, "metadata": { "title": "Rollout plan" } }

roadmap

Monthly roadmap grid.

FieldTypeRequiredDescription
titlestringNoRoadmap title
monthsarrayNoMonth columns
months[].monthstringNoMonth label
months[].itemsarrayNoItems in that month
months[].items[].idstringNoItem id
months[].items[].textstringNoItem label
{ "pin_type": "roadmap", "pin_config": { "title": "Product roadmap", "months": [ { "month": "May", "items": [{ "id": "m1", "text": "API v1" }] }, { "month": "Jun", "items": [{ "id": "m2", "text": "Mobile app" }] } ] }, "metadata": { "title": "Roadmap" } }

calendar

Calendar with events.

FieldTypeRequiredDescription
weekStartsOnnumberNo0 = Sunday, 1 = Monday
eventsarrayNoCalendar events
events[].idstringNoEvent id
events[].titlestringNoEvent title
events[].startstringNoStart date (YYYY-MM-DD)
events[].endstringNoEnd date
{ "pin_type": "calendar", "pin_config": { "weekStartsOn": 0, "events": [ { "id": "e1", "title": "Sprint review", "start": "2026-05-01", "end": "2026-05-01" }, { "id": "e2", "title": "Release", "start": "2026-05-15", "end": "2026-05-15" } ] }, "metadata": { "title": "Team calendar" } }

kanban-board

Kanban board with columns and cards.

FieldTypeRequiredDescription
columnsarrayYes (min 1)Board columns
columns[].idstringYesColumn id
columns[].titlestringYesColumn title
columns[].cardsarrayNoCards in column
{ "pin_type": "kanban-board", "pin_config": { "columns": [ { "id": "todo", "title": "To do", "cards": [{ "id": "c1", "title": "Design API" }] }, { "id": "done", "title": "Done", "cards": [] } ] }, "metadata": { "title": "Sprint board" } }

checklist

Checklist with toggleable items.

FieldTypeRequiredDescription
titlestringNoChecklist title
itemsarrayYes (min 1)Checklist rows
items[].idstringYesItem id
items[].namestringYesItem label
items[].checkedbooleanNoChecked state
{ "pin_type": "checklist", "pin_config": { "title": "Launch checklist", "items": [ { "id": "c1", "name": "QA pass", "checked": false }, { "id": "c2", "name": "Deploy prod", "checked": false } ] }, "metadata": { "title": "Launch checklist" } }

comparison

Side-by-side comparison with column headings, one item per line, optional highlights and row matches.

FieldTypeRequiredDescription
titlestringNoPin title
leftobjectYesLeft column
left.labelstringYesLeft heading
left.bodystringYesMultiline text (one row per line)
rightobjectYesRight column
right.labelstringYesRight heading
right.bodystringYesMultiline text (one row per line)
highlightedLines.leftnumber[]NoZero-based line indices to highlight (left)
highlightedLines.rightnumber[]NoZero-based line indices to highlight (right)
matchesarrayNoAligned row pairs marked as matching
matches[].leftnumberYesLeft row index
matches[].rightnumberYesRight row index
showVsBadgebooleanNoShow VS badge between columns (default true)
{ "pin_type": "comparison", "pin_config": { "title": "Tech stack", "left": { "label": "Our stack", "body": "Next.js\nTypeScript\nFirebase" }, "right": { "label": "Their stack", "body": "React\nJavaScript\nMongoDB" }, "highlightedLines": { "left": [0], "right": [0] }, "matches": [{ "left": 0, "right": 0 }, { "left": 1, "right": 1 }], "showVsBadge": true }, "metadata": { "title": "Stack comparison" } }

Collection of link cards.

FieldTypeRequiredDescription
linksarrayNoLink entries
links[].titlestringNoLink title
links[].urlstringNoLink URL
links[].descriptionstringNoShort description
{ "pin_type": "links", "pin_config": { "links": [ { "title": "Documentation", "url": "https://pindown.ai" }, { "title": "GitHub", "url": "https://github.com/pindownai" } ] }, "metadata": { "title": "Useful links" } }

process-flow

Swimlane workflow map with nodes, edges, team roster, and bottleneck views.

FieldTypeRequiredDescription
titlestringNoFlow title
defaultViewstringNo"onboarding" or "bottlenecks"
swimlanesarrayYes (min 1)Lane definitions
swimlanes[].idstringYesLane id
swimlanes[].titlestringYesLane label
nodesarrayYes (min 1)Steps in the flow
nodes[].idstringYesNode id
nodes[].swimlanestringYesLane id this node belongs to
nodes[].labelstringYesStep label
nodes[].statusstringNo"smooth", "bottleneck", or "warning"
edgesarrayNo{ source, target } connections between node ids
{ "pin_type": "process-flow", "pin_config": { "title": "Developer Onboarding Flow", "defaultView": "onboarding", "swimlanes": [ { "id": "po", "title": "Product Owner" }, { "id": "dev", "title": "Developer" } ], "nodes": [ { "id": "1", "swimlane": "po", "label": "Ticket Refinement", "status": "smooth" }, { "id": "2", "swimlane": "dev", "label": "Implementation", "status": "smooth" } ], "edges": [{ "source": "1", "target": "2" }] }, "metadata": { "title": "Onboarding flow" } }

funnel

Conversion funnel with ordered stages, drop-off rates, and optional biggest-leak highlight.

FieldTypeRequiredDescription
titlestringNoFunnel title
subtitlestringNoe.g. time range
valueFormatstringNo"number", "percent", or "currency"
currencystringNoISO currency when valueFormat is "currency"
highlightBiggestDropbooleanNoHighlight the largest stage drop-off
stagesarrayYes (min 1)Top-to-bottom stages
stages[].idstringYesStage id
stages[].labelstringYesStage label
stages[].valuenumberYesAbsolute count at this stage
{ "pin_type": "funnel", "pin_config": { "title": "Signup funnel", "subtitle": "Last 30 days", "valueFormat": "number", "highlightBiggestDrop": true, "stages": [ { "id": "visit", "label": "Website Visits", "value": 12400 }, { "id": "signup", "label": "Sign Up Started", "value": 4820 }, { "id": "paid", "label": "Upgraded to Paid", "value": 640 } ] }, "metadata": { "title": "Conversion funnel" } }

decision-matrix

Weighted criteria matrix to score options and surface a winner.

FieldTypeRequiredDescription
titlestringNoMatrix title
subtitlestringNoSubtitle
maxScorenumberNoMax score per criterion (default 5)
optionsarrayYes (min 2)Columns to compare
options[].idstringYesOption id
options[].labelstringYesOption label
criteriaarrayYes (min 1)Scoring rows
criteria[].idstringYesCriterion id
criteria[].labelstringYesCriterion label
criteria[].weightnumberNoWeight multiplier (default 1)
criteria[].scoresobjectYes{ [optionId]: number } scores
{ "pin_type": "decision-matrix", "pin_config": { "title": "Backend Framework Decision", "maxScore": 5, "options": [ { "id": "next", "label": "Next.js" }, { "id": "remix", "label": "Remix" } ], "criteria": [ { "id": "dx", "label": "Developer experience", "weight": 2, "scores": { "next": 5, "remix": 4 } }, { "id": "perf", "label": "Performance", "weight": 1, "scores": { "next": 4, "remix": 5 } } ] }, "metadata": { "title": "Framework decision" } }

okr

Objectives and key results with progress, confidence, and status.

FieldTypeRequiredDescription
titlestringNoOKR set title
subtitlestringNoSubtitle
periodstringNoe.g. "Q2 2026"
objectivesarrayYes (min 1)Objectives list
objectives[].idstringYesObjective id
objectives[].titlestringYesObjective title
objectives[].keyResultsarrayYes (min 1)Key results
objectives[].keyResults[].idstringYesKR id
objectives[].keyResults[].titlestringYesKR title
objectives[].keyResults[].currentnumberNoCurrent value
objectives[].keyResults[].targetnumberNoTarget value
objectives[].keyResults[].unitstringNoUnit label, e.g. "%"
objectives[].keyResults[].confidencenumberNo0–100 confidence
objectives[].keyResults[].statusstringNo"on-track", "at-risk", or "off-track"
{ "pin_type": "okr", "pin_config": { "title": "Q2 Product OKRs", "period": "Apr – Jun 2026", "objectives": [ { "id": "obj-1", "title": "Accelerate paid conversion", "keyResults": [ { "id": "kr-1", "title": "Trial-to-paid rate", "current": 18, "target": 25, "unit": "%", "confidence": 65, "status": "at-risk" } ] } ] }, "metadata": { "title": "Q2 OKRs" } }

Chat, agents & interactive

user-story

User story with acceptance criteria.

FieldTypeRequiredDescription
userStorystringYesUser story text
titlestringNoStory title
acceptanceCriteriastringNoGiven/When/Then criteria
{ "pin_type": "user-story", "pin_config": { "title": "Login", "userStory": "As a user,\nI want to log in\nso that I can access my workspace.", "acceptanceCriteria": "Given valid credentials\nWhen I sign in\nThen I reach the home page" }, "metadata": { "title": "US-101 Login" } }

chat

Chat / discussion placeholder.

FieldTypeRequiredDescription
titlestringNoChat title
placeholderstringNoInput placeholder text
{ "pin_type": "chat", "pin_config": { "title": "Team chat", "placeholder": "Write a message…" }, "metadata": { "title": "Discussion" } }

mastra

Mastra workflow or agent pin. Schema is open — pass workflow/agent identifiers as needed.

FieldTypeRequiredDescription
modestringNo"workflow" or "agent"
workflowIdstringNoMastra workflow id
agentIdstringNoMastra agent id
{ "pin_type": "mastra", "pin_config": { "mode": "workflow", "workflowId": "my-workflow-id" }, "metadata": { "title": "Automation runner" } }

realtime-canvas

Collaborative whiteboard / canvas room.

FieldTypeRequiredDescription
titlestringNoCanvas title
descriptionstringNoShort description
roomIdstringNoRealtime room identifier
{ "pin_type": "realtime-canvas", "pin_config": { "title": "Brainstorm", "description": "Sprint planning whiteboard", "roomId": "room-sprint-42" }, "metadata": { "title": "Whiteboard" } }

Interactive feedback

Pins that collect input in realtime (votes, form answers, star scores). Data lives in separate Firebase paths — not in the pin document.

poll

Live single-question poll. Votes are stored per viewer in Firebase (pin_poll_votes/{pinId}/votes/{userId}), not in the pin document.

FieldTypeRequiredDescription
questionstringYesPoll question
optionsarrayYes (min 2)Answer choices
options[].idstringYesOption id
options[].labelstringYesOption label
statusstringNo"open" or "closed"
showVoteCountbooleanNoShow counts and percentages after voting
allowChangeVotebooleanNoLet voters change their selection
{ "pin_type": "poll", "pin_config": { "question": "Which feature should we ship next?", "status": "open", "showVoteCount": true, "options": [ { "id": "a", "label": "Mobile app" }, { "id": "b", "label": "API v2" } ] }, "metadata": { "title": "Feature poll" } }

survey

Multi-question form. Responses are stored per respondent in Firebase (pin_survey_responses/{pinId}/responses/{userId}). Owners and editors can read aggregated results in the pin UI.

FieldTypeRequiredDescription
titlestringNoSurvey title
descriptionstringNoIntro shown above the form
statusstringNo"open" or "closed"
allowEditResponsebooleanNoLet respondents update answers after submit
questionsarrayYes (min 1)Question list
questions[].idstringYesQuestion id
questions[].labelstringYesQuestion text
questions[].typestringYes"short-text", "long-text", "single-choice", "multiple-choice", or "scale"
questions[].requiredbooleanNoWhether an answer is required
questions[].optionsarrayNoChoices for single/multi choice ({ id, label })
questions[].scaleMinnumberNoScale minimum (default 1)
questions[].scaleMaxnumberNoScale maximum (default 5)
{ "pin_type": "survey", "pin_config": { "title": "Sprint Retro", "description": "Quick feedback on the last sprint.", "status": "open", "allowEditResponse": false, "questions": [ { "id": "q1", "label": "What went well?", "type": "long-text", "required": true }, { "id": "q2", "label": "Team velocity", "type": "scale", "required": true, "scaleMin": 1, "scaleMax": 5 }, { "id": "q3", "label": "Biggest blocker", "type": "single-choice", "options": [ { "id": "scope", "label": "Scope creep" }, { "id": "none", "label": "No major blockers" } ] } ] }, "metadata": { "title": "Sprint retro" } }

rating

Star rating (default 1–5, half stars optional). Rate one prompt or multiple items (e.g. content, delivery, overall). Scores are stored per viewer in Firebase (pin_ratings/{pinId}/ratings/{userId}). Owners and editors see per-item distribution and averages in the Results tab; optional showAverage displays live per-item averages to viewers.

FieldTypeRequiredDescription
titlestringNoPin title
descriptionstringNoIntro shown above all rating rows
promptstringNoSingle rating question (used when items is empty)
itemsarrayNoMultiple things to rate — each with id, label, optional description, required
statusstringNo"open" or "closed"
maxStarsnumberNo3, 4, or 5 (default 5)
allowHalfStarsbooleanNoAllow 0.5 increments (default true)
allowChangeRatingbooleanNoLet users update their scores after submitting
showAveragebooleanNoShow per-item live averages to viewers (default true)

Stored rating at pin_ratings/{pinId}/ratings/{userId}: either a single value (0.5 … maxStars) or a scores object mapping itemId → star value. Half-star steps apply when allowHalfStars is enabled.

Example stored response (multi-item):

{ "scores": { "demo": 4.5, "clarity": 5, "overall": 4 }, "display_name": "Alex", "rated_at": 1718208000000 }

Create example:

{ "pin_type": "rating", "pin_config": { "title": "Session feedback", "description": "Rate each part of today's walkthrough.", "status": "open", "maxStars": 5, "allowHalfStars": true, "allowChangeRating": true, "showAverage": true, "items": [ { "id": "demo", "label": "Demo usefulness", "required": true }, { "id": "clarity", "label": "Clarity of explanation", "required": true }, { "id": "overall", "label": "Overall experience", "required": true } ] }, "metadata": { "title": "Demo rating" } }

Validation errors

CodeWhen
INVALID_PIN_TYPEUnknown pin_type value
PIN_CONFIG_INVALIDpin_config fails schema for the given type
metadata.title is requiredMissing title on create

Next steps