{"openapi":"3.1.0","info":{"title":"PUBlish public API","version":"1.0.0","description":"Read-only public endpoints for discovering and reading PUBlish content. No API key required. CORS-open. Designed for AI agents, third-party integrations, and developer tooling building on top of PUBlish.\n\nSee https://pub-lish.com/integrations for a human-friendly tour of every endpoint with copy-paste snippets for common platforms.\n\nFor native tool-calling, the same surface is exposed at /api/mcp via the Model Context Protocol (MCP) — see the MCP section below.","contact":{"name":"PUBlish","url":"https://www.pub-lish.com/integrations"},"license":{"name":"Public read access","url":"https://www.pub-lish.com/integrations"}},"servers":[{"url":"https://www.pub-lish.com","description":"Production"}],"tags":[{"name":"Authors","description":"Discover and fetch PUBlish writers. Use search when you don't know the slug yet; use the single-author endpoint when you do."},{"name":"Pieces","description":"Discover, search, and read pieces. The recent endpoint surfaces the latest cross-author feed; the search endpoint runs full-text across headline, standfirst, and body; the single-piece endpoint returns full content by id."},{"name":"MCP","description":"Native Model Context Protocol server exposing every read endpoint as a JSON-RPC tool. Connect Claude Desktop, Cursor, or any MCP-capable client to /api/mcp. The MCP server also supports auto-discovery via /.well-known/mcp.json."},{"name":"Embed","description":"SVG badges and a one-paste JavaScript widget that renders author cards, lists, and badges on any site. Designed for storefronts, blogs, email signatures, and LLM-built static sites."},{"name":"Write","description":"Authenticated write surface. Push pieces INTO PUBlish via Bearer-token POST. Every API-created piece lands as a draft — the writer reviews + publishes manually. No automation can put live content under a writer's byline."}],"paths":{"/api/public/authors/{slug}":{"get":{"tags":["Authors"],"summary":"Get one author","description":"Return the canonical structured profile for one PUBlish writer by their slug. Includes name, bio, role, niche, location, avatar, identity_verified state, social links, piece count, last_published_at, and stable URLs (profile, badge, feed_json, feed_rss).","operationId":"getAuthor","parameters":[{"name":"slug","in":"path","required":true,"description":"The author's URL slug, e.g. 'jane-novak'.","schema":{"type":"string"}}],"responses":{"200":{"description":"Author found","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"author":{"$ref":"#/components/schemas/Author"}},"required":["ok","author"]}}}},"404":{"description":"No author at this slug","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotFound"}}}}}}},"/api/public/authors/search":{"get":{"tags":["Authors"],"summary":"Search authors","description":"Substring search across display_name, niche, role, and bio. Verified writers rank first; ties broken by piece count.","operationId":"searchAuthors","parameters":[{"name":"q","in":"query","required":true,"description":"Free-text query (topic, name fragment, niche keyword).","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Maximum hits. Default 10, max 50.","schema":{"type":"integer","minimum":1,"maximum":50,"default":10}}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"query":{"type":"string"},"count":{"type":"integer"},"results":{"type":"array","items":{"$ref":"#/components/schemas/AuthorHit"}}},"required":["ok","results"]}}}}}}},"/api/public/pieces/{id}":{"get":{"tags":["Pieces"],"summary":"Get one piece","description":"Return the full content of one piece by id in JSON Feed 1.1 item shape. Drafts and pending pieces return 404; only editor_status='approved' pieces are public.","operationId":"getPiece","parameters":[{"name":"id","in":"path","required":true,"description":"The piece's id (UUID).","schema":{"type":"string"}}],"responses":{"200":{"description":"Piece found","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"piece":{"$ref":"#/components/schemas/Piece"}},"required":["ok","piece"]}}}},"404":{"description":"Piece not found, or not public","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotFound"}}}}}}},"/api/public/pieces/recent":{"get":{"tags":["Pieces"],"summary":"Cross-author recent feed","description":"Return the N most-recent approved pieces, optionally filtered by category.","operationId":"recentPieces","parameters":[{"name":"category","in":"query","required":false,"description":"Category filter.","schema":{"type":"string","enum":["building","leading","culture","money","life"]}},{"name":"limit","in":"query","required":false,"description":"Maximum pieces. Default 20, max 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Recent pieces","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"category":{"type":["string","null"]},"count":{"type":"integer"},"items":{"type":"array","items":{"$ref":"#/components/schemas/PieceListItem"}}},"required":["ok","items"]}}}}}}},"/api/public/pieces/search":{"get":{"tags":["Pieces"],"summary":"Full-text piece search","description":"Substring search across headline, standfirst, and body of every approved piece. Hits rank by match site (headline > standfirst > body), then by recency.","operationId":"searchPieces","parameters":[{"name":"q","in":"query","required":true,"description":"Free-text search query.","schema":{"type":"string"}},{"name":"category","in":"query","required":false,"schema":{"type":"string","enum":["building","leading","culture","money","life"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"query":{"type":"string"},"category":{"type":["string","null"]},"count":{"type":"integer"},"results":{"type":"array","items":{"$ref":"#/components/schemas/PieceHit"}}},"required":["ok","results"]}}}}}}},"/api/mcp":{"post":{"tags":["MCP"],"summary":"MCP JSON-RPC endpoint","description":"JSON-RPC 2.0 over HTTP POST. Implements the Model Context Protocol (2025-06-18) with the following tools:\n\n  • search_authors(query, limit?)\n  • get_author(slug)\n  • recent_pieces(category?, limit?)\n  • get_piece(id)\n  • search_pieces(query, category?, limit?)\n\nThe same data the REST endpoints above expose, with MCP tool semantics so AI clients (Claude Desktop, Cursor, MCP-capable agents) can call PUBlish natively. See https://modelcontextprotocol.io for the protocol spec.\n\nAuto-discoverable at /.well-known/mcp.json.","operationId":"mcpJsonRpc","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcRequest"}}}},"responses":{"200":{"description":"JSON-RPC response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcResponse"}}}}}},"get":{"tags":["MCP"],"summary":"MCP server discovery doc","description":"Returns a small JSON discovery document — useful for humans hitting the URL directly or for crawlers that don't speak JSON-RPC.","operationId":"mcpDiscovery","responses":{"200":{"description":"Server discovery","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/embed/{slug}/badge.svg":{"get":{"tags":["Embed"],"summary":"Live SVG badge","description":"Returns a self-contained SVG pill that any site can embed with `<img src=...>`. Renders the writer's name + a verified tick when their identity is verified. Updates automatically when the writer renames or changes verification on PUBlish.","operationId":"badgeSvg","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"theme","in":"query","required":false,"description":"Color theme.","schema":{"type":"string","enum":["light","dark"],"default":"light"}},{"name":"tone","in":"query","required":false,"description":"Pass \"verified\" to show the gold verified tick.","schema":{"type":"string","enum":["verified"]}}],"responses":{"200":{"description":"SVG badge","content":{"image/svg+xml":{"schema":{"type":"string","format":"binary"}}}}}}},"/api/v1/pieces":{"post":{"tags":["Write"],"summary":"Create a draft piece","description":"Submit a piece on behalf of the authenticated key's owner. The submission lands as editor_status='draft' — the writer reviews it in their /desk/edit editor and publishes manually (which is what flips it to 'approved' and fires the public flow). No API call can put live content under a writer's byline.\n\nSend Bearer auth via the standard Authorization header. Mint keys in /desk/edit/online-presence → API keys.","operationId":"createDraftPiece","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePieceBody"}}}},"responses":{"201":{"description":"Draft created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePieceResponse"}}}},"400":{"description":"Validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotFound"}}}},"401":{"description":"Missing or malformed Authorization header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotFound"}}}},"403":{"description":"Invalid, revoked, or insufficient-scope key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotFound"}}}}}}},"/api/v1/pieces/me":{"get":{"tags":["Write"],"summary":"List your recent pieces","description":"Return the authenticated key owner's recent submissions across all editor_status values, so an automation can verify drafts landed and grab edit URLs. Filter with ?status=draft|pending|approved|rejected|changes_requested.","operationId":"listMyPieces","security":[{"ApiKey":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["draft","pending","approved","rejected","changes_requested"]}}],"responses":{"200":{"description":"Your pieces","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"count":{"type":"integer"},"pieces":{"type":"array","items":{"$ref":"#/components/schemas/MyPieceListItem"}}},"required":["ok","pieces"]}}}},"401":{"description":"Missing or malformed Authorization header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotFound"}}}}}}},"/embed.js":{"get":{"tags":["Embed"],"summary":"Universal widget script","description":"A single small JS file that scans the host page for `data-publish-widget` elements and renders one of four widgets: badge, card, list, bio. Pure ES5, no dependencies, CORS-open, idempotent re-scans on SPA mutations.","operationId":"embedJs","responses":{"200":{"description":"JavaScript","content":{"application/javascript":{"schema":{"type":"string","format":"binary"}}}}}}}},"components":{"securitySchemes":{"ApiKey":{"type":"http","scheme":"bearer","description":"Bearer token minted by a writer at /desk/edit/online-presence → API keys. Format: pk_live_<64 hex chars>. Scoped to pieces:write — drafts only."}},"schemas":{"CreatePieceBody":{"type":"object","required":["headline","body_md"],"properties":{"headline":{"type":"string","maxLength":200},"sub":{"type":["string","null"],"maxLength":400},"body_md":{"type":"string","maxLength":100000},"category":{"type":"string","enum":["building","leading","culture","money","life","civic","ideas","society"],"default":"building"},"tags":{"type":"array","items":{"type":"string","maxLength":32},"maxItems":8},"frame":{"type":"string","enum":["lesson","origin","contrarian","before_after"],"default":"lesson"},"style":{"type":"string","default":"essay"},"locale":{"type":"string","default":"en"},"external_url":{"type":["string","null"],"format":"uri","description":"If the piece was originally published elsewhere, stored on fields.external_url for canonical attribution."}}},"CreatePieceResponse":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["draft"]},"created_at":{"type":"string","format":"date-time"},"edit_url":{"type":"string","format":"uri"},"profile_url":{"type":["string","null"],"format":"uri"}},"required":["ok","id","status","edit_url"]},"MyPieceListItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"headline":{"type":"string"},"sub":{"type":["string","null"]},"category":{"type":"string"},"status":{"type":"string","enum":["draft","pending","approved","rejected","changes_requested"]},"locale":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string","format":"date-time"},"edit_url":{"type":"string","format":"uri"}}},"Author":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"bio":{"type":["string","null"]},"role":{"type":["string","null"]},"niche":{"type":["string","null"]},"location":{"type":["string","null"]},"avatar_url":{"type":["string","null"],"format":"uri"},"website":{"type":["string","null"],"format":"uri"},"identity_verified":{"type":"boolean"},"website_verified":{"type":"boolean"},"socials":{"type":"object","properties":{"x":{"type":["string","null"],"format":"uri"},"linkedin":{"type":["string","null"],"format":"uri"},"facebook":{"type":["string","null"],"format":"uri"},"youtube":{"type":["string","null"],"format":"uri"},"instagram":{"type":["string","null"],"format":"uri"},"newsletter":{"type":["string","null"],"format":"uri"}}},"stats":{"type":"object","properties":{"pieces_count":{"type":"integer"},"last_published_at":{"type":["string","null"],"format":"date-time"}}},"urls":{"type":"object","properties":{"profile":{"type":"string","format":"uri"},"badge_svg":{"type":"string","format":"uri"},"feed_json":{"type":"string","format":"uri"},"feed_rss":{"type":"string","format":"uri"}}},"joined_at":{"type":["string","null"],"format":"date-time"}},"required":["slug","name","identity_verified","website_verified","urls"]},"AuthorHit":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"role":{"type":["string","null"]},"niche":{"type":["string","null"]},"bio_snippet":{"type":["string","null"]},"avatar_url":{"type":["string","null"],"format":"uri"},"identity_verified":{"type":"boolean"},"pieces_count":{"type":"integer"},"urls":{"type":"object","properties":{"profile":{"type":"string","format":"uri"},"badge_svg":{"type":"string","format":"uri"},"feed_json":{"type":"string","format":"uri"}}}}},"Piece":{"type":"object","properties":{"id":{"type":"string","format":"uri"},"url":{"type":"string","format":"uri"},"title":{"type":"string"},"summary":{"type":"string"},"content_html":{"type":["string","null"]},"content_text":{"type":"string"},"date_published":{"type":"string","format":"date-time"},"date_modified":{"type":"string","format":"date-time"},"tags":{"type":"array","items":{"type":"string"}},"category":{"type":["string","null"]},"kind":{"type":"string"},"authors":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string","format":"uri"},"avatar":{"type":["string","null"],"format":"uri"},"identity_verified":{"type":"boolean"}}}}}},"PieceListItem":{"type":"object","properties":{"id":{"type":"string","format":"uri"},"url":{"type":"string","format":"uri"},"title":{"type":"string"},"summary":{"type":"string"},"date_published":{"type":"string","format":"date-time"},"category":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"authors":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string","format":"uri"},"identity_verified":{"type":"boolean"}}}}}},"PieceHit":{"type":"object","properties":{"id":{"type":"string","format":"uri"},"url":{"type":"string","format":"uri"},"title":{"type":"string"},"summary":{"type":"string"},"snippet":{"type":["string","null"],"description":"Excerpt around the matched term in the body. Null when the match was in the headline or standfirst."},"date_published":{"type":"string","format":"date-time"},"category":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"match_site":{"type":"string","enum":["headline","standfirst","body"]},"authors":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"url":{"type":"string","format":"uri"},"identity_verified":{"type":"boolean"}}}}}},"NotFound":{"type":"object","properties":{"ok":{"type":"boolean","enum":[false]},"reason":{"type":"string"}}},"JsonRpcRequest":{"type":"object","properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"oneOf":[{"type":"string"},{"type":"integer"},{"type":"null"}]},"method":{"type":"string","description":"MCP methods include initialize, tools/list, tools/call, ping, prompts/list, resources/list."},"params":{"type":"object"}},"required":["jsonrpc","method"]},"JsonRpcResponse":{"oneOf":[{"type":"object","properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"oneOf":[{"type":"string"},{"type":"integer"},{"type":"null"}]},"result":{"type":"object"}},"required":["jsonrpc","id","result"]},{"type":"object","properties":{"jsonrpc":{"type":"string","enum":["2.0"]},"id":{"oneOf":[{"type":"string"},{"type":"integer"},{"type":"null"}]},"error":{"type":"object","properties":{"code":{"type":"integer"},"message":{"type":"string"},"data":{}},"required":["code","message"]}},"required":["jsonrpc","id","error"]}]}}},"x-publish":{"docs_url":"https://www.pub-lish.com/integrations","llms_txt_url":"https://www.pub-lish.com/llms.txt","mcp_discovery_url":"https://www.pub-lish.com/.well-known/mcp.json","contact_url":"https://www.pub-lish.com/integrations"}}