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).
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.
| Field | Type | Required | Description |
|---|---|---|---|
content | string | No | Markdown body |
collaboration.enabled | boolean | No | Set 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.
| Field | Type | Required | Description |
|---|---|---|---|
title | string | No | Main headline |
text | string | No | Body copy |
subtext | string | No | Secondary paragraph |
textPosition | string | No | "left" or "right" — text side relative to media |
mediaType | string | No | "image" or "embed" |
imageConfig.url | string | No* | Image URL (when mediaType is "image") |
imageConfig.alt | string | No | Image alt text |
imageConfig.fileId | string | No | Reference to an uploaded file |
embedConfig.type | string | No* | e.g. "youtube", "loom", "figma" |
embedConfig.url | string | No* | Embed URL (when mediaType is "embed") |
embedConfig.aspectRatio | string | No | e.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.
| Field | Type | Required | Description |
|---|---|---|---|
heading | string | Yes | Main heading |
subheading | string | No | Secondary line |
{
"pin_type": "intro",
"pin_config": {
"heading": "Project overview",
"subheading": "Q1 initiative"
},
"metadata": { "title": "Intro" }
}image
Single image display.
| Field | Type | Required | Description |
|---|---|---|---|
url | string | No | Image URL |
altText | string | No | Alt text |
fit | string | No | "cover", "contain", etc. |
{
"pin_type": "image",
"pin_config": {
"url": "https://example.com/photo.png",
"altText": "Dashboard screenshot",
"fit": "cover"
},
"metadata": { "title": "Screenshot" }
}gallery
Grid of images.
| Field | Type | Required | Description |
|---|---|---|---|
images | array | No | List of image objects |
images[].url | string | No | Image URL |
images[].alt | string | No | Alt text |
images[].fileId | string | No | Reference 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" }
}Data & metrics
stat-cards
KPI cards with optional trend indicators.
| Field | Type | Required | Description |
|---|---|---|---|
cards | array | Yes (min 1) | Stat card list |
cards[].title | string | Yes | Metric label |
cards[].value | string | number | Yes | Metric value |
cards[].change | string | No | Change label, e.g. "+18.2%" |
cards[].trend | string | No | "up", "down", "neutral" |
cards[].icon | string | No | Icon 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.).
| Field | Type | Required | Description |
|---|---|---|---|
chartType | string | No | e.g. "line", "bar", "pie", "area", "radar" |
title | string | No | Chart title |
data | array | No | Data points (objects with arbitrary keys) |
xAxis | string | No | Key used for X axis |
yAxis | string | No | Key used for Y axis |
dataKeys | string[] | No | Series 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.
| Field | Type | Required | Description |
|---|---|---|---|
columns | array | Yes (min 1) | Column definitions |
columns[].id | string | Yes | Column key (used in row cells) |
columns[].name | string | Yes | Column header label |
columns[].type | string | No | e.g. "text", "number", "date" |
rows | array | No | Row objects |
rows[].id | string | No | Row identifier |
rows[].cells | object | No | { [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.
| Field | Type | Required | Description |
|---|---|---|---|
json | any | No | Parsed JSON value |
jsonString | string | No | JSON as string (alternative to json) |
title | string | No | Viewer 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.
| Field | Type | Required | Description |
|---|---|---|---|
json | array | No | Parsed JSON array |
jsonString | string | No | JSON 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.
| Field | Type | Required | Description |
|---|---|---|---|
csvText | string | No | Raw CSV text |
csvData | array | No | Parsed rows as objects |
fileName | string | No | Display 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" }
}Files & embeds
embed
Embedded video or external content.
| Field | Type | Required | Description |
|---|---|---|---|
url | string | No | Embed URL |
type | string | No | e.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.
| Field | Type | Required | Description |
|---|---|---|---|
pdf.url | string | Yes | PDF file URL |
pdf.fileName | string | No | Display filename |
pdf.title | string | No | Document 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.
| Field | Type | Required | Description |
|---|---|---|---|
excel.url | string | Yes | Spreadsheet URL |
excel.fileName | string | No | Display filename |
excel.title | string | No | Document 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.
| Field | Type | Required | Description |
|---|---|---|---|
files | array | No | File metadata objects |
displayMode | string | No | e.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.
| Field | Type | Required | Description |
|---|---|---|---|
code | string | Yes¹ | Mermaid source |
diagram | string | Yes¹ | Alternative to code |
title | string | No | Diagram 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" }
}timeline
Chronological timeline.
| Field | Type | Required | Description |
|---|---|---|---|
mode | string | No | e.g. "alternating", "left", "right" |
items | array | No | Timeline entries |
items[].title | string | No | Date or label |
items[].cardTitle | string | No | Event title |
items[].cardDetailedText | string | No | Event 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.
| Field | Type | Required | Description |
|---|---|---|---|
steps | array | Yes (min 1) | Step list |
steps[].title | string | Yes | Step title |
steps[].description | string | No | Step 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" }
}roadmap
Monthly roadmap grid.
| Field | Type | Required | Description |
|---|---|---|---|
title | string | No | Roadmap title |
months | array | No | Month columns |
months[].month | string | No | Month label |
months[].items | array | No | Items in that month |
months[].items[].id | string | No | Item id |
months[].items[].text | string | No | Item 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.
| Field | Type | Required | Description |
|---|---|---|---|
weekStartsOn | number | No | 0 = Sunday, 1 = Monday |
events | array | No | Calendar events |
events[].id | string | No | Event id |
events[].title | string | No | Event title |
events[].start | string | No | Start date (YYYY-MM-DD) |
events[].end | string | No | End 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.
| Field | Type | Required | Description |
|---|---|---|---|
columns | array | Yes (min 1) | Board columns |
columns[].id | string | Yes | Column id |
columns[].title | string | Yes | Column title |
columns[].cards | array | No | Cards 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.
| Field | Type | Required | Description |
|---|---|---|---|
title | string | No | Checklist title |
items | array | Yes (min 1) | Checklist rows |
items[].id | string | Yes | Item id |
items[].name | string | Yes | Item label |
items[].checked | boolean | No | Checked 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" }
}links
Collection of link cards.
| Field | Type | Required | Description |
|---|---|---|---|
links | array | No | Link entries |
links[].title | string | No | Link title |
links[].url | string | No | Link URL |
links[].description | string | No | Short description |
{
"pin_type": "links",
"pin_config": {
"links": [
{ "title": "Documentation", "url": "https://pindown.ai" },
{ "title": "GitHub", "url": "https://github.com/pindownai" }
]
},
"metadata": { "title": "Useful links" }
}Stories, chat & agents
user-story
User story with acceptance criteria.
| Field | Type | Required | Description |
|---|---|---|---|
userStory | string | Yes | User story text |
title | string | No | Story title |
acceptanceCriteria | string | No | Given/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.
| Field | Type | Required | Description |
|---|---|---|---|
title | string | No | Chat title |
placeholder | string | No | Input 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.
| Field | Type | Required | Description |
|---|---|---|---|
mode | string | No | "workflow" or "agent" |
workflowId | string | No | Mastra workflow id |
agentId | string | No | Mastra agent id |
{
"pin_type": "mastra",
"pin_config": {
"mode": "workflow",
"workflowId": "my-workflow-id"
},
"metadata": { "title": "Automation runner" }
}realtime-canvas
Collaborative whiteboard / canvas room.
| Field | Type | Required | Description |
|---|---|---|---|
title | string | No | Canvas title |
description | string | No | Short description |
roomId | string | No | Realtime room identifier |
{
"pin_type": "realtime-canvas",
"pin_config": {
"title": "Brainstorm",
"description": "Sprint planning whiteboard",
"roomId": "room-sprint-42"
},
"metadata": { "title": "Whiteboard" }
}Validation errors
| Code | When |
|---|---|
INVALID_PIN_TYPE | Unknown pin_type value |
PIN_CONFIG_INVALID | pin_config fails schema for the given type |
metadata.title is required | Missing title on create |
Next steps
- Create a Pin — full create endpoint reference
- Update a Pin — partial updates to
pin_config - Client SDK — typed
PinConfigByTypehelpers