PUBlish
Developers← Back to PUBlish

PUBlish · Integrations

Publish once on PUBlish. Show up everywhere.

Three integration paths, all free, none require a PUBlish API key:

The snippets below use a placeholder slug (your-slug). Sign in and we’ll fill in your real slug everywhere on this page.

Feeds

Your live URLs

Every PUBlish author has these endpoints. Subscribe an RSS reader, point a Next.js fetch, or hand the JSON URL to your LLM.

JSON Feedhttps://pub-lish.com/en/author/your-slug/feed.json
RSS / Atomhttps://pub-lish.com/en/author/your-slug/feed.xml
Author profilehttps://pub-lish.com/author/your-slug

Ask AI

Get walked through it

Open the AI you use, the prompt is pre-written with your URLs. The AI will tell you exactly which setting to open in your platform and what to paste.

I want to import the latest pieces from my PUBlish author profile into my [Shopify / WordPress / Webflow / Squarespace / other] site. Walk me through it step-by-step — I'm not technical.

My PUBlish JSON Feed URL: https://pub-lish.com/en/author/your-slug/feed.json
My PUBlish RSS URL:       https://pub-lish.com/en/author/your-slug/feed.xml
My PUBlish profile URL:   https://pub-lish.com/author/your-slug

Tell me which platform-specific setting to open, what to click, and exactly what to paste. If the platform supports RSS feeds natively (most blog platforms do), prefer that. If it doesn't, write me the smallest possible code snippet that pulls the JSON Feed and renders the posts.
Open in ChatGPTOpen in ClaudeOpen in Gemini

WordPress / WooCommerce

Official plugin + RSS subscribe

Easiest: install the PUBlish Author Badge plugin. For full auto-import, paste the PHP below into a custom plugin or your theme's functions.php.

1. Author badge (recommended)

[publish_badge]

Install the “PUBlish Author Badge” plugin from the WordPress plugin directory, then drop the shortcode anywhere.

2. Auto-import latest pieces as WP posts

<!-- Add to functions.php or a custom plugin to import latest PUBlish pieces as WP posts -->
add_action('rest_api_init', function () {
  register_rest_route('publish/v1', '/sync', [
    'methods' => 'POST',
    'callback' => function () {
      $response = wp_remote_get('https://pub-lish.com/en/author/your-slug/feed.json');
      $body = json_decode(wp_remote_retrieve_body($response), true);
      foreach ($body['items'] as $item) {
        // Idempotent: skip if a post with this PUBlish source URL already exists.
        $existing = get_posts(['meta_key' => 'publish_source', 'meta_value' => $item['url'], 'numberposts' => 1]);
        if (!empty($existing)) continue;
        $post_id = wp_insert_post([
          'post_title'   => $item['title'],
          'post_content' => $item['content_html'],
          'post_excerpt' => $item['summary'],
          'post_status'  => 'publish',
          'post_date'    => mysql2date('Y-m-d H:i:s', $item['date_published']),
          'meta_input'   => ['publish_source' => $item['url']],
        ]);
      }
      return ['imported' => count($body['items'])];
    },
  ]);
});

POSTing to /wp-json/publish/v1/sync pulls the feed and creates one WP post per piece (idempotent — duplicates are skipped). Wire it to a cron job or a Make / Zapier hourly trigger.

Shopify

Theme snippet + badge

Drop the Liquid below into any section to show your latest PUBlish piece on a storefront page. Or install the PUBlish Author Badge from the Shopify App Store for a one-tap setup.

<!-- Add to a theme section to render the latest PUBlish piece on any storefront page -->
<div id="latest-publish-piece" style="padding:24px;background:#FAF7F0;border-radius:8px;">
  <p style="font-family:Georgia,serif;font-style:italic;color:#888;margin:0;">Loading latest piece…</p>
</div>
<script>
fetch('https://pub-lish.com/en/author/your-slug/feed.json')
  .then(r => r.json())
  .then(j => {
    var item = j.items[0];
    if (!item) return;
    document.getElementById('latest-publish-piece').innerHTML =
      '<a href="' + item.url + '" target="_blank" rel="noopener" style="text-decoration:none;color:inherit;display:block;">' +
      '<p style="font-family:Inter,sans-serif;font-size:11px;font-weight:700;letter-spacing:0.14em;text-transform:uppercase;color:#B8923E;margin:0 0 6px;">Latest on PUBlish</p>' +
      '<h3 style="font-family:Georgia,serif;font-weight:600;margin:0 0 8px;font-size:22px;">' + item.title + '</h3>' +
      '<p style="font-family:Georgia,serif;font-style:italic;color:#4a4640;margin:0;">' + (item.summary || '') + '</p>' +
      '</a>';
  });
</script>

Add via Shopify admin → Online Store → Themes → Customize → Add Section → Custom Liquid → paste.

Next.js

App Router page that renders the feed

Drop into your site's blog route. Caches for 10 minutes; revalidates on demand. Works with any deployment provider (Vercel, Netlify, self-hosted).

// app/blog/page.tsx — Next.js App Router
export const revalidate = 600; // refresh hourly

export default async function BlogPage() {
  const res = await fetch('https://pub-lish.com/en/author/your-slug/feed.json', { next: { revalidate: 600 } });
  const feed = await res.json();
  return (
    <div>
      <h1>{feed.title}</h1>
      <ul>
        {feed.items.map((item: any) => (
          <li key={item.id}>
            <a href={item.url}>{item.title}</a>
            <p>{item.summary}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}

Webflow / Squarespace / Wix

Embed element snippet

Most no-code builders support a raw-HTML embed element. Paste the snippet below; it fetches the JSON Feed at runtime and renders the latest 5 pieces.

<!-- Add to a Webflow Embed element. Pulls and renders the latest 5 pieces. -->
<div id="publish-feed" style="display:flex;flex-direction:column;gap:24px;"></div>
<script>
fetch('https://pub-lish.com/en/author/your-slug/feed.json')
  .then(r => r.json())
  .then(j => {
    document.getElementById('publish-feed').innerHTML = j.items.slice(0, 5).map(item =>
      '<article><h3><a href="' + item.url + '" target="_blank" rel="noopener">' + item.title + '</a></h3>' +
      '<p>' + (item.summary || '') + '</p>' +
      '<small>' + new Date(item.date_published).toLocaleDateString() + '</small></article>'
    ).join('');
  });
</script>

Realtime push

Publish webhook — auto-syndicate the moment you ship

Set a webhook URL on /desk/edit/online-presence, then every piece you publish on PUBlish POSTs the JSON Feed item to that URL within 5 minutes. Same shape as the JSON Feed; signed with X-Publish-Signature so your receiver can verify it's really PUBlish.

What you receive

POST https://your-site.com/api/publish-webhook
Content-Type: application/json
X-Publish-Event: piece.published
X-Publish-Signature: sha256=<hmac-sha256(secret, raw_body)>

{
  "id":          "https://pub-lish.com/en/read/<piece-id>",
  "url":         "https://pub-lish.com/en/read/<piece-id>",
  "title":       "Your piece headline",
  "summary":     "Standfirst / first 240 chars of body",
  "content_text": "Full markdown body",
  "date_published": "2026-06-29T18:00:00.000Z",
  "date_modified":  "2026-06-29T18:00:00.000Z",
  "tags":  ["building", "ai"],
  "authors": [{ "name": "Jane Novak", "url": "https://pub-lish.com/author/jane-novak", "avatar": "..." }],
  "piece": {
    "piece_id":          "abc-123",
    "author_slug":       "jane-novak",
    "author_avatar_url": "...",
    "category":          "building",
    "kind":              "piece"
  }
}

Verifying the signature (Node.js example)

// In your /api/publish-webhook handler:
import crypto from 'crypto';

const rawBody = await req.text();
const signature = req.headers.get('x-publish-signature');
const expected = 'sha256=' + crypto
  .createHmac('sha256', process.env.PUBLISH_WEBHOOK_SECRET)
  .update(rawBody)
  .digest('hex');

if (signature !== expected) {
  return new Response('Bad signature', { status: 401 });
}

const payload = JSON.parse(rawBody);
// payload.piece.piece_id is unique — use it for dedup.
// payload.title, content_text, tags, etc. map to your CMS.

Your secret is auto-generated the first time you save a webhook URL on Online presence. Copy it from there into your receiver’s environment variables. We attempt the POST exactly once per piece and log the response code on the submission row.

MCP

Native tools for Claude Desktop, Cursor, MCP agents

PUBlish exposes a Model Context Protocol server with four tools — search_authors, get_author, recent_pieces, get_piece. Add the endpoint to any MCP-capable client and the AI can call PUBlish directly instead of HTTP-fetching JSON.

Claude Desktop config (claude_desktop_config.json)

{
  "mcpServers": {
    "publish": {
      "type": "http",
      "url": "https://pub-lish.com/api/mcp"
    }
  }
}

Cursor / other MCP clients

# Add to your client's MCP settings:
https://pub-lish.com/api/mcp

Auto-discoverable at https://pub-lish.com/.well-known/mcp.json — clients that scan domains for MCP endpoints find this listed first before any per-company server.

Public API · pieces

Single piece + cross-author recent feed

Read pieces from PUBlish via clean JSON endpoints. Single piece by id; cross-author recent feed filterable by category. Same envelope as the per-author feed.

Get a single piece

GET https://pub-lish.com/api/public/pieces/<piece-id>

Response:
{
  "ok": true,
  "piece": {
    "id":              "https://pub-lish.com/en/read/<piece-id>",
    "url":             "https://pub-lish.com/en/read/<piece-id>",
    "title":           "...",
    "summary":         "...",
    "content_html":    "...",
    "content_text":    "...",
    "date_published":  "...",
    "date_modified":   "...",
    "tags":            ["building", "ai"],
    "category":        "building",
    "kind":            "piece",
    "authors": [{
      "name":               "...",
      "slug":               "jane-novak",
      "url":                "...",
      "avatar":             "...",
      "identity_verified":  true
    }],
    "piece": {
      "piece_id":   "...",
      "author_slug": "jane-novak",
      "category":    "building",
      "kind":        "piece"
    }
  }
}

Search pieces by content (full-text)

GET https://pub-lish.com/api/public/pieces/search?q=hiring+engineers&limit=20

Optional category filter: &category=building (or leading / culture / money / life)
Limit: 1..100 (default 20)

Response:
{
  "ok":       true,
  "query":    "hiring engineers",
  "category": null,
  "count":    8,
  "results": [
    {
      "id":             "https://pub-lish.com/en/read/<piece-id>",
      "url":            "https://pub-lish.com/en/read/<piece-id>",
      "title":          "...",
      "summary":        "...",
      "snippet":        "…contextual snippet around the match in the body…",
      "date_published": "...",
      "category":       "building",
      "match_site":     "headline | standfirst | body",
      "tags":           ["building", "hiring"],
      "authors":        [{ "name": "...", "slug": "...", "identity_verified": true }]
    },
    ...
  ]
}

Hits rank by match site (headline > standfirst > body), then by recency. snippet is only populated when the match was in the body (not the headline / standfirst — those already speak for themselves). Cached 5 min server-side.

Cross-author recent feed

GET https://pub-lish.com/api/public/pieces/recent?category=building&limit=20

Valid categories: building, leading, culture, money, life
Limit: 1..100 (default 20)
Omit category to get recent across every category.

Response:
{
  "ok":       true,
  "category": "building",
  "count":    20,
  "items": [
    {
      "id":             "https://pub-lish.com/en/read/<piece-id>",
      "url":            "https://pub-lish.com/en/read/<piece-id>",
      "title":          "...",
      "summary":        "...",
      "date_published": "...",
      "category":       "building",
      "tags":           ["building", "ai"],
      "authors":        [{ "name": "...", "slug": "...", "url": "...", "identity_verified": true }]
    },
    ...
  ]
}

Returns up to 100 pieces per call. Cached 10 min server-side; CORS-open. Pieces with editor_status ≠ approved (drafts, pending) never appear here.

Public API · authors

Author + search JSON endpoints

Auth-free, CORS-open JSON endpoints. Same data as the public profile page; structured for LLM ingestion and third-party integrations. No API key required.

Get a single author

GET https://pub-lish.com/api/public/authors/your-slug

Response:
{
  "ok": true,
  "author": {
    "slug": "your-slug",
    "name": "...",
    "bio": "...",
    "role": "...",
    "niche": "...",
    "avatar_url": "...",
    "identity_verified": true,
    "website_verified": true,
    "socials": { "x": "...", "linkedin": "...", "newsletter": "...", ... },
    "stats": { "pieces_count": 42, "last_published_at": "2026-06-29T..." },
    "urls": {
      "profile":   "https://pub-lish.com/author/your-slug",
      "badge_svg": "https://pub-lish.com/embed/your-slug/badge.svg",
      "feed_json": "https://pub-lish.com/en/author/your-slug/feed.json",
      "feed_rss":  "https://pub-lish.com/en/author/your-slug/feed.xml"
    }
  }
}

Search authors by topic, name, niche, or bio

GET https://pub-lish.com/api/public/authors/search?q=ai+policy&limit=10

Response:
{
  "ok": true,
  "query": "ai policy",
  "count": 5,
  "results": [
    {
      "slug": "jane-novak",
      "name": "Jane Novak",
      "role": "Founder",
      "niche": "ai policy · regulation",
      "bio_snippet": "Reporting on...",
      "avatar_url": "...",
      "identity_verified": true,
      "pieces_count": 14,
      "urls": { "profile": "...", "badge_svg": "...", "feed_json": "..." }
    },
    ...
  ]
}

Verified writers rank first; ties broken by piece count. Substring match across display_name, niche, role, and bio. Cached 5 min server-side; CORS-open for any browser host.

One-paste embed

Universal <script> widgets

One <script> tag, four widgets. No platform-specific code, no API keys. Works on any site that accepts a script tag in HTML — including pages built by an LLM. Idempotent re-scans on SPA navigation.

Latest piece card

<div data-publish-widget="card" data-slug="your-slug"></div>
<script src="https://pub-lish.com/embed.js" defer></script>

Recent pieces list

<div data-publish-widget="list" data-slug="your-slug" data-limit="5"></div>
<script src="https://pub-lish.com/embed.js" defer></script>

Author bio block

<div data-publish-widget="bio" data-slug="your-slug"></div>
<script src="https://pub-lish.com/embed.js" defer></script>

Optional attributes: data-theme="dark" for dark backgrounds, data-locale="en" (default en), data-verified="false" on the badge widget to hide the verified tick.

Spec

OpenAPI 3.1 spec

Every public endpoint formally described in OpenAPI 3.1. Drop into Postman, Insomnia, openapi-typescript, swagger-codegen, Stoplight, Redocly — anywhere an OpenAPI-aware tool runs.

https://pub-lish.com/api/openapi.json

Use cases: auto-generate a typed PUBlish client in Go / Python / Java / Rust / TypeScript in five minutes; render live docs at your own domain via Redocly / Stoplight / Mintlify; import into Postman for an exploratory test collection; feed it to an MCP client that converts OpenAPI to tool calls.

Write API

POST a draft from your CMS or AI agent

The missing half of the syndication story. Mint a Bearer key on /desk/edit/online-presence → API keys, then POST a piece into PUBlish from anywhere. Every API-created piece lands as a DRAFT — the writer reviews and publishes manually. No automation can put live content under a writer's byline.

cURL

curl -X POST https://pub-lish.com/api/v1/pieces \
  -H "Authorization: Bearer pk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "headline": "The quiet trade-off behind pricing power",
    "sub": "Why margin outlasts growth.",
    "body_md": "# The quiet trade-off\n\nWhen you raise prices…",
    "category": "money",
    "tags": ["pricing", "unit economics"],
    "external_url": "https://your-site.com/posts/pricing-power"
  }'

Node

const res = await fetch('https://pub-lish.com/api/v1/pieces', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.PUBLISH_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    headline: 'The quiet trade-off behind pricing power',
    body_md: '# The quiet trade-off…',
    category: 'money',
    tags: ['pricing', 'unit economics'],
  }),
});
const { id, edit_url } = await res.json();
console.log('Draft landed:', edit_url);

Confirm the draft landed

curl https://pub-lish.com/api/v1/pieces/me?status=draft \
  -H "Authorization: Bearer pk_live_…"

Required fields: headline + body_md. Optional: sub, category, tags, frame, locale, external_url. Limits: headline ≤ 200 chars, sub ≤ 400, body ≤ 100 000, tags ≤ 8 (each ≤ 32 chars). Keys are scoped to pieces:write only — they cannot publish, edit existing pieces, or read other writers’ content.

Schema

JSON Feed 1.1 format

PUBlish follows the standard JSON Feed 1.1 spec. Every item carries id, url, title, summary, content_html, content_text, date_published, date_modified, tags, and authors. Documented at jsonfeed.org/version/1.1.

Tools that consume JSON Feed natively: Feedly, Readwise Reader, Inoreader, NetNewsWire, Reeder. RSS readers consume the /feed.xml endpoint without configuration.

© PUBlish← Back to PUBlish