{"openapi":"3.1.0","info":{"title":"NowPinned Integrations API","version":"1.0.0","description":"Publish files to permanent NowPinned links from scripts and AI assistants. Authenticate with a dashboard API key or OAuth 2.1 bearer token. Create and publishing operations require an Idempotency-Key header. The MCP server at /api/mcp provides the same capabilities."},"servers":[{"url":"https://manage.nowpinned.com"}],"security":[{"apiKey":[]},{"oauth2":[]}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"API key from the dashboard Integrations page (pin_live_…)."},"oauth2":{"type":"oauth2","description":"OAuth 2.1 with PKCE via NowPinned sign-in. MCP clients discover this automatically from /.well-known/oauth-protected-resource.","flows":{"authorizationCode":{"authorizationUrl":"https://gbxyopqmrbfrtzxulaqh.supabase.co/auth/v1/oauth/authorize","tokenUrl":"https://gbxyopqmrbfrtzxulaqh.supabase.co/auth/v1/oauth/token","scopes":{"openid":"Confirm your identity","profile":"See your basic profile"}}}}},"schemas":{"ErrorEnvelope":{"type":"object","required":["success","error"],"properties":{"success":{"type":"boolean","const":false},"error":{"type":"string","description":"Human-readable message."},"code":{"type":"string","description":"Stable error code, e.g. UNAUTHORISED, FEATURE_GATED, VALIDATION_FAILED, NOT_FOUND, CONFLICT, PAYLOAD_TOO_LARGE, RATE_LIMITED."}}},"Site":{"type":"object","required":["id","name","slug"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string"}}},"Pin":{"type":"object","required":["id","site_id","display_name","slug","inbound_email_address","active_version_id","folder"],"properties":{"id":{"type":"string","format":"uuid"},"site_id":{"type":"string","format":"uuid"},"display_name":{"type":"string"},"slug":{"type":"string"},"inbound_email_address":{"type":"string"},"active_version_id":{"type":["string","null"],"format":"uuid"},"folder":{"description":"The folder this pin is in, or null.","oneOf":[{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},{"type":"null"}]}}},"Version":{"type":"object","required":["id","pin_id","version_number","file_name","file_url","file_type","file_size_bytes","status","change_label","internal_label","created_at"],"properties":{"id":{"type":"string","format":"uuid"},"pin_id":{"type":"string","format":"uuid"},"version_number":{"type":"integer"},"file_name":{"type":"string"},"file_url":{"type":"string"},"file_type":{"type":"string","enum":["pdf","docx","xlsx","csv","image","html"]},"file_size_bytes":{"type":"integer"},"status":{"type":"string","description":"staged | live | archived | scheduled | pending_approval | rejected"},"change_label":{"type":["string","null"]},"internal_label":{"type":["string","null"],"description":"Private dashboard-only label. Never shown to viewers."},"created_at":{"type":"string","format":"date-time"}}},"VersionHistoryItem":{"type":"object","required":["id","version_number","status","is_live","file_name","file_type","internal_label","created_at"],"properties":{"id":{"type":"string","format":"uuid"},"version_number":{"type":"integer"},"status":{"type":"string","description":"staged | live | archived | scheduled | pending_approval | rejected"},"is_live":{"type":"boolean","description":"True for the version currently served at the public URL."},"file_name":{"type":"string"},"file_type":{"type":"string","enum":["pdf","docx","xlsx","csv","image","html"]},"change_label":{"type":["string","null"]},"internal_label":{"type":["string","null"],"description":"Private dashboard-only label. Never shown to viewers."},"created_at":{"type":"string","format":"date-time"}}},"Folder":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"SecureAccess":{"type":"object","required":["pin_id","enabled","access_rule","contact_fields","pin_required","remember_days","source","has_pin_override"],"properties":{"pin_id":{"type":"string","format":"uuid"},"enabled":{"type":"boolean"},"access_rule":{"type":"string","enum":["contact","pin","pin_contact"]},"contact_fields":{"type":"array","items":{"type":"string","enum":["name","email","phone"]}},"pin_required":{"type":"boolean"},"remember_days":{"type":"integer"},"source":{"type":"string","enum":["pin_override","folder","default"]},"has_pin_override":{"type":"boolean"}}}}},"paths":{"/api/v1/openapi.json":{"get":{"security":[],"operationId":"getOpenApiDocument","summary":"Get the public OpenAPI 3.1 contract","responses":{"200":{"description":"OpenAPI document.","content":{"application/json":{"schema":{"type":"object","required":["openapi","info","paths"],"properties":{"openapi":{"type":"string"},"info":{"type":"object","additionalProperties":true},"paths":{"type":"object","additionalProperties":true}}}}}}}}},"/api/v1/readme":{"get":{"security":[],"operationId":"getPinnedReadme","summary":"Get the full NowPinned operating guide for developers and AI assistants","responses":{"200":{"description":"Full operating guide.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["readme"],"properties":{"readme":{"type":"string"}}}}}}}}}}},"/api/v1/sites":{"get":{"operationId":"listSites","summary":"List the sites this principal can publish to","responses":{"200":{"description":"Sites accessible to the key.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"sites":{"type":"array","items":{"$ref":"#/components/schemas/Site"}}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/api/v1/pins":{"get":{"operationId":"listPins","summary":"List pins (permanent links) with their live version ids","parameters":[{"name":"site_id","in":"query","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Pins for the site(s).","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"pins":{"type":"array","items":{"$ref":"#/components/schemas/Pin"}}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createPin","summary":"Create a new pin (a permanent public URL) on a site","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Unique key (1-120 chars) per logical operation. Replaying the same key with the exact same payload returns the original result without re-executing. Reusing it with changed input returns 409.","schema":{"type":"string","maxLength":120}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["site_id","display_name"],"properties":{"site_id":{"type":"string","format":"uuid"},"display_name":{"type":"string","maxLength":50},"folder_id":{"type":["string","null"],"format":"uuid","description":"Optional folder to place it in."}}}}}},"responses":{"201":{"description":"Pin created.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"pin":{"$ref":"#/components/schemas/Pin"},"permanent_link":{"type":"string"}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/api/v1/pins/{pin_id}":{"patch":{"operationId":"renamePin","summary":"Rename a pin — the permanent URL does not change","parameters":[{"name":"pin_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["display_name"],"properties":{"display_name":{"type":"string","maxLength":100}}}}}},"responses":{"200":{"description":"Pin renamed.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"message":{"type":"string"},"pin_id":{"type":"string","format":"uuid"},"display_name":{"type":"string"}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/api/v1/pins/{pin_id}/folder":{"patch":{"operationId":"movePin","summary":"Move a pin into a folder (or null to remove it from its folder)","parameters":[{"name":"pin_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["folder_id"],"properties":{"folder_id":{"type":["string","null"],"format":"uuid"}}}}}},"responses":{"200":{"description":"Pin moved.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"message":{"type":"string"},"pin_id":{"type":"string","format":"uuid"},"folder_id":{"type":["string","null"],"format":"uuid"}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/api/v1/sites/{site_id}/folders":{"get":{"operationId":"listFolders","summary":"List the folders on a site","parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Folders for the site.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"folders":{"type":"array","items":{"$ref":"#/components/schemas/Folder"}}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"post":{"operationId":"createFolder","summary":"Create a folder on a site","parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"Unique key (1-120 chars) per logical operation. Replaying the same key with the exact same payload returns the original result without re-executing. Reusing it with changed input returns 409.","schema":{"type":"string","maxLength":120}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":80}}}}}},"responses":{"201":{"description":"Folder created.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"folder":{"$ref":"#/components/schemas/Folder"}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/api/v1/pins/{pin_id}/secure-access":{"get":{"operationId":"getSecureAccess","summary":"Read a pin’s secure-access gate (effective policy + where it comes from)","parameters":[{"name":"pin_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The effective secure-access policy.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"secure_access":{"$ref":"#/components/schemas/SecureAccess"}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}},"patch":{"operationId":"setSecureAccess","summary":"Set a pin’s secure-access gate (Pro plan) — require contact details and/or a PIN","description":"Pass inherit:true to clear the pin override and inherit from its folder/default. Otherwise set enabled + the policy. Enabling requires the Pro plan.","parameters":[{"name":"pin_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"inherit":{"type":"boolean","description":"Clear the pin override and inherit."},"enabled":{"type":"boolean"},"access_rule":{"type":"string","enum":["contact","pin","pin_contact"]},"contact_fields":{"type":"array","items":{"type":"string","enum":["name","email","phone"]}},"pin":{"type":["string","null"],"description":"4-6 digit PIN."},"remember_days":{"type":"integer","minimum":1,"maximum":30}}}}}},"responses":{"200":{"description":"Updated secure-access policy.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"secure_access":{"$ref":"#/components/schemas/SecureAccess"}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/api/v1/pins/{pin_id}/active-version":{"get":{"operationId":"getActiveVersion","summary":"Get the currently published version for a pin","parameters":[{"name":"pin_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The live version, or null when nothing is published.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"version":{"oneOf":[{"$ref":"#/components/schemas/Version"},{"type":"null"}]}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/api/v1/versions/{version_id}/content":{"get":{"operationId":"getVersionFileContent","summary":"Fetch a version's raw file content","description":"Redirects (307) to a short-lived signed URL for the original uploaded file. Owner access — bypasses the public viewer gate.","parameters":[{"name":"version_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"307":{"description":"Redirect to a short-lived signed URL for the file content.","headers":{"Location":{"schema":{"type":"string","format":"uri"}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/api/v1/pins/{pin_id}/active-version/content":{"get":{"operationId":"getActiveVersionFileContent","summary":"Fetch the current live version's raw file content for a pin","description":"Redirects (307) to a short-lived signed URL for the pin's live original file. 404 when nothing is published.","parameters":[{"name":"pin_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"307":{"description":"Redirect to a short-lived signed URL for the file content.","headers":{"Location":{"schema":{"type":"string","format":"uri"}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/api/v1/uploads/direct":{"post":{"operationId":"uploadFile","summary":"Upload a file in one call (base64 or HTML) and stage it as a new version","description":"Send the file content inline and receive the staged version plus its permanent link. Publish it with publishVersion. Limited to 20 requests/minute per key. Provide exactly one of base64_content or html_content (html_content requires mime_type text/html).","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Unique key (1-120 chars) per logical operation. Replaying the same key with the exact same payload returns the original result without re-executing. Reusing it with changed input returns 409.","schema":{"type":"string","maxLength":120}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pin_id","filename","mime_type"],"properties":{"pin_id":{"type":"string","format":"uuid"},"filename":{"type":"string","maxLength":180},"mime_type":{"type":"string","description":"application/pdf, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, text/csv, image/png, image/jpeg, image/webp, or text/html."},"base64_content":{"type":"string","description":"Base64-encoded file bytes (max 20 MB decoded)."},"html_content":{"type":"string","description":"Raw HTML document (max 20 MB)."},"internal_label":{"type":["string","null"],"description":"Optional private team note (dashboard-only, never shown to viewers)."},"change_label":{"type":"string","description":"Optional public label shown to viewers. Omit to stage with no public label."}}}}}},"responses":{"201":{"description":"Version staged.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"version":{"$ref":"#/components/schemas/Version"},"permanent_link":{"type":"string","description":"The pin’s public URL (shows the live version until this one is published)."},"staged_preview_url":{"type":"string","description":"Team-gated draft preview of this staged version (not public)."}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (20 requests/minute per key). Respect Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/api/v1/uploads/prepare":{"post":{"operationId":"prepareUpload","summary":"Get a signed URL for uploading large files directly to storage","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Unique key (1-120 chars) per logical operation. Replaying the same key with the exact same payload returns the original result without re-executing. Reusing it with changed input returns 409.","schema":{"type":"string","maxLength":120}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pin_id","mime_type","size"],"properties":{"pin_id":{"type":"string","format":"uuid"},"mime_type":{"type":"string"},"size":{"type":"integer","minimum":1,"description":"File size in bytes (max 20 MB)."}}}}}},"responses":{"200":{"description":"Signed upload target. PUT the file bytes to signed_url, then call completeUpload.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"signed_url":{"type":"string"},"token":{"type":"string"},"storage_path":{"type":"string"},"upload_id":{"type":"string","format":"uuid"},"file_name":{"type":"string"},"version_number":{"type":"integer"},"file_ext":{"type":"string"}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/api/v1/uploads/complete":{"post":{"operationId":"completeUpload","summary":"Finalise a prepared upload as a staged version","parameters":[{"name":"Idempotency-Key","in":"header","required":true,"description":"Unique key (1-120 chars) per logical operation. Replaying the same key with the exact same payload returns the original result without re-executing. Reusing it with changed input returns 409.","schema":{"type":"string","maxLength":120}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pin_id","storage_path","upload_id","mime_type","size"],"properties":{"pin_id":{"type":"string","format":"uuid"},"storage_path":{"type":"string"},"upload_id":{"type":"string","format":"uuid"},"mime_type":{"type":"string"},"size":{"type":"integer","minimum":1},"internal_label":{"type":["string","null"],"description":"Optional private team note (dashboard-only, never shown to viewers)."},"change_label":{"type":"string","description":"Optional public label shown to viewers. Omit to stage with no public label."}}}}}},"responses":{"201":{"description":"Version staged.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"version":{"$ref":"#/components/schemas/Version"},"staged_preview_url":{"type":"string","description":"Team-gated draft preview of this staged version (not public)."}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/api/v1/versions/{version_id}/publish":{"post":{"operationId":"publishVersion","summary":"Publish a staged version — the permanent link updates instantly","parameters":[{"name":"version_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":true,"description":"Unique key (1-120 chars) per logical operation. Replaying the same key with the exact same payload returns the original result without re-executing. Reusing it with changed input returns 409.","schema":{"type":"string","maxLength":120}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"change_label":{"type":"string","description":"Public label shown to viewers. Omit to publish with no public label."},"internal_label":{"type":["string","null"],"description":"Private dashboard-only label. Never shown to viewers."},"announce":{"type":"boolean","description":"Show the change badge and notify subscribers. Requires change_label."},"scheduled_for":{"type":"string","format":"date-time","description":"Optional ISO 8601 timestamp. If set, the version is scheduled to publish then instead of immediately."}}}}}},"responses":{"200":{"description":"Version published (or scheduled).","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["message","status","pin_id","permanent_link"],"properties":{"message":{"type":"string"},"status":{"type":"string","description":"live | scheduled | pending_approval"},"pin_id":{"type":"string","format":"uuid"},"permanent_link":{"type":"string","format":"uri","description":"The pin’s permanent public URL."}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/api/v1/pins/{pin_id}/versions":{"get":{"operationId":"listVersions","summary":"List a pin’s version history (newest first), including archived versions","description":"Use this to find a previous version to restore.","parameters":[{"name":"pin_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Version history.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"versions":{"type":"array","items":{"$ref":"#/components/schemas/VersionHistoryItem"}}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/api/v1/versions/{version_id}/restore":{"post":{"operationId":"restoreVersion","summary":"Roll a pin back by restoring an archived version — it becomes live again","description":"The previously-live version is automatically archived. Find the version id with listVersions.","parameters":[{"name":"version_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Version restored and live.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"message":{"type":"string"},"pin_id":{"type":"string","format":"uuid"}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/api/v1/versions/{version_id}/label":{"patch":{"operationId":"relabelVersion","summary":"Relabel a version — set the public and/or internal label (null clears one)","parameters":[{"name":"version_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Provide change_label and/or internal_label. Each accepts null to clear it.","properties":{"change_label":{"type":["string","null"],"maxLength":100,"description":"Public label shown to viewers."},"internal_label":{"type":["string","null"],"maxLength":100,"description":"Private dashboard-only label. Never shown to viewers."}}}}}},"responses":{"200":{"description":"Label updated.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","properties":{"message":{"type":"string"},"pin_id":{"type":"string","format":"uuid"},"change_label":{"type":["string","null"]},"internal_label":{"type":["string","null"]}}}}}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing, invalid, expired, or revoked API key/OAuth bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"The principal cannot access this site or the requested feature is not included in its plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"The requested site, pin, version, or folder was not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"State conflict, including reuse of an idempotency key with changed input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"413":{"description":"Request body exceeds the route limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited. Respect the Retry-After response header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}}}}