API Documentation
Programmatically manage your boards and pins via HTTPS. JSON in, JSON out. API access is part of the Enterprise plan.
Authentication
Generate an API key from Settings → API keys. Send it with every request as a Bearer token:
Authorization: Bearer ptp_live_xxxxxxxxxxxxxxxxxxxxxxxxEach key has a set of scopes that limit what it can do:
boards:read— list your boardsboards:write— create / update boardspins:read— read pins on your boardspins:write— create / update / delete pins
Base URL
https://corkboard.social/api/public/v1Boards
/api/public/v1/boardscurl -H "Authorization: Bearer ptp_live_..." \
https://corkboard.social/api/public/v1/boards?limit=25{
"boards": [
{
"id": "uuid", "title": "...", "slug": "...",
"description": "...", "visibility": "public",
"pins_count": 12, "links_count": 4,
"views_count": 320,
"created_at": "...", "updated_at": "..."
}
]
}/api/public/v1/boardsRequest body:
{
"title": "My board", // string, 1–120, required
"description": "Optional", // string, ≤500, optional
"visibility": "public" // "public" | "unlisted" | "private", default "public"
}curl -X POST \
-H "Authorization: Bearer ptp_live_..." \
-H "Content-Type: application/json" \
-d '{"title":"My board","visibility":"public"}' \
https://corkboard.social/api/public/v1/boardsResponse (201):
{
"board": {
"id": "uuid",
"title": "My board",
"slug": "my-board",
"description": null,
"visibility": "public",
"created_at": "2026-06-21T10:00:00.000Z"
}
}Pins
/api/public/v1/pins?board_id=<uuid>curl -H "Authorization: Bearer ptp_live_..." \
"https://corkboard.social/api/public/v1/pins?board_id=BOARD_UUID&limit=50"Response (200):
{
"pins": [
{
"id": "uuid",
"board_id": "uuid",
"slug": "pin-lxyz",
"name": "My pin",
"photo_url": "https://...",
"short_desc": "Short text",
"badges": ["new"],
"pos_x": 120, "pos_y": 80, "rotation": 0,
"pin_variant": "pin-01",
"style": null,
"likes_count": 0,
"comments_count": 0,
"created_at": "2026-06-21T10:00:00.000Z",
"updated_at": "2026-06-21T10:00:00.000Z"
}
]
}/api/public/v1/pinsRequest body:
{
"board_id": "BOARD_UUID", // required
"name": "My pin", // required, 1–120 chars
"slug": "my-pin", // optional; auto-generated if omitted
"photo_url": "https://...", // optional, string | null
"short_desc": "Description", // optional, ≤500 chars
"badges": ["new","hot"], // optional, up to 12 strings
"pos_x": 120, // optional, number (default 0)
"pos_y": 80, // optional, number (default 0)
"rotation": 0, // optional, number (default 0)
"pin_variant":"pin-01", // optional, one of "pin-01" … "pin-10" (see Pin variants)
"style": { /* Pin style object — see Styles & widgets below */ }
}curl -X POST \
-H "Authorization: Bearer ptp_live_..." \
-H "Content-Type: application/json" \
-d '{
"board_id":"BOARD_UUID",
"name":"My pin",
"photo_url":"https://example.com/p.jpg",
"badges":["new","featured"],
"pos_x":120, "pos_y":80
}' \
https://corkboard.social/api/public/v1/pinsResponse (201):
{
"pin": {
"id": "uuid",
"board_id": "uuid",
"slug": "my-pin",
"name": "My pin",
"photo_url": "https://example.com/p.jpg",
"short_desc": null,
"badges": ["new","featured"],
"pos_x": 120, "pos_y": 80, "rotation": 0,
"pin_variant": "pin-01",
"style": null,
"likes_count": 0,
"comments_count": 0,
"created_at": "2026-06-21T10:00:00.000Z",
"updated_at": "2026-06-21T10:00:00.000Z"
}
}/api/public/v1/pins/:pinIdcurl -H "Authorization: Bearer ptp_live_..." \
https://corkboard.social/api/public/v1/pins/PIN_UUIDResponse (200): { pin: Pin } — see schema below.
/api/public/v1/pins/:pinIdRequest body — any subset of:
{
"name": "Renamed", // 1–120 chars
"photo_url": "https://...", // string | null (send null to clear)
"short_desc": "New desc", // string | null, ≤500 chars
"badges": ["sale"], // replaces the array, up to 12
"pos_x": 300, // number
"pos_y": 120, // number
"rotation": 15, // number (degrees)
"pin_variant": "pin-03", // "pin-01" … "pin-10"
"style": { /* Pin style object, see below */ } // or null to clear
}curl -X PATCH \
-H "Authorization: Bearer ptp_live_..." \
-H "Content-Type: application/json" \
-d '{"name":"Renamed","pos_x":300,"pos_y":120}' \
https://corkboard.social/api/public/v1/pins/PIN_UUIDResponse (200): { pin: Pin } — the full updated pin.
/api/public/v1/pins/:pinIdcurl -X DELETE \
-H "Authorization: Bearer ptp_live_..." \
https://corkboard.social/api/public/v1/pins/PIN_UUIDResponse (200):
{ "ok": true, "deleted": "PIN_UUID" }What the API can not do
To keep boards fair, the public API is intentionally scoped to content you own. The following are not exposed via API — and we won't add them:
- Likes / reactions on boards, pins, links or comments. Engagement counts can't be inflated through the API — they only change when real users interact through the app.
- View counts (
views_count,likes_count,comments_count) — read-only. - Follows, comments, votes, or notifications on other people's content.
- Other users' boards, pins, or profile data — even if public. Use the regular website to browse those.
- Admin / moderation actions (bans, reports, plan changes, audit logs).
If a request looks like an attempt to write to one of these, you'll get 403 or 404.
Pin variants, widgets & styles
pin_variant)"pin-01" | "pin-02" | "pin-03" | "pin-04" | "pin-05"
"pin-06" | "pin-07" | "pin-08" | "pin-09" | "pin-10"Default is "pin-01". Unknown values fall back to pin-01 when rendered.
style object — full schema{
paper: "plain" | "lined" | "grid" | "aged" | "kraft", // default "plain"
// "grid","aged","kraft" require Premium pin styles
tornEdges: { top: boolean, right: boolean, // default all false
bottom: boolean, left: boolean },
attachment: {
type: "pushpin" | "tape" | "clip" | "none", // default "pushpin"
// "tape" & "clip" require Premium pin styles
color: "#RRGGBB" | null // hex, optional
},
opacity: number, // 0.9 – 1.0, default 1
tint: "#RRGGBB" | null, // overlay tint, optional
widget: { // optional embedded widget (see below)
type: "image" | "text" | "youtube" | "spotify" | "audio"
| "link" | "quote" | "code" | "map" | "checklist",
data: { /* widget-specific payload */ }
} | null,
width: number | null, // px, optional explicit size
height: number | null
}Plan-gated fields (premium paper textures, tape/clip attachments) are accepted in the request but will only render to viewers on a plan that allows them. The board owner's plan is what counts, not the API caller's.
style.widgetdata shape. Send only the fields listed for that type.// image — extra image inside the pin
{ type: "image", data: { url: string, alt?: string } }
// text — rich text block
{ type: "text", data: { content: string, align?: "left"|"center"|"right" } }
// youtube — embedded video
{ type: "youtube", data: { videoId: string, start?: number } }
// spotify — embedded track/playlist/album
{ type: "spotify", data: { url: string } }
// audio — direct audio file
{ type: "audio", data: { url: string, title?: string } }
// link — preview card
{ type: "link", data: { url: string, title?: string, description?: string, image?: string } }
// quote — pull quote
{ type: "quote", data: { text: string, author?: string } }
// code — code snippet
{ type: "code", data: { code: string, language?: string } }
// map — pinned location
{ type: "map", data: { lat: number, lng: number, label?: string, zoom?: number } }
// checklist — interactive checklist
{ type: "checklist", data: { items: { text: string, checked?: boolean }[] } }Some widget types (audio, code, map, checklist, embeds) are considered advanced widgets and require a plan with can_advanced_widgets. Unauthorized widgets are rejected with 400.
curl -X POST \
-H "Authorization: Bearer ptp_live_..." \
-H "Content-Type: application/json" \
-d '{
"board_id":"BOARD_UUID",
"name":"Demo video",
"pos_x":200, "pos_y":160, "rotation":-3,
"pin_variant":"pin-04",
"style": {
"paper":"lined",
"attachment":{"type":"tape","color":"#facc15"},
"tornEdges":{"top":false,"right":false,"bottom":true,"left":false},
"widget":{
"type":"youtube",
"data":{"videoId":"dQw4w9WgXcQ","start":0}
}
}
}' \
https://corkboard.social/api/public/v1/pinsSchemas
{
id: string // uuid
title: string
slug: string
description: string | null
visibility: "public" | "unlisted" | "private"
pins_count: number
links_count: number
views_count: number
created_at: string // ISO 8601
updated_at: string // ISO 8601
}{
id: string // uuid
board_id: string // uuid
slug: string
name: string
photo_url: string | null
short_desc: string | null
badges: string[]
pos_x: number
pos_y: number
rotation: number // degrees
pin_variant: string // "pin-01" … "pin-10"
style: PinStyle | null // see Styles & widgets section
likes_count: number
comments_count: number
created_at: string // ISO 8601
updated_at: string // ISO 8601
}{ "error": "Human-readable message" }Errors & limits
Errors come back as { error: string } with these status codes:
400— invalid input401— missing or invalid Bearer token403— token missing required scope404— resource not found, or you don't own it500— unexpected server error
A key only sees resources owned by the user who created it. Revoked keys stop working immediately.