Index: src/routes/posts.js
===================================================================
--- src/routes/posts.js	(revision 75bda38ace3a3eff7e9ea9d7676a2ad33a8ad24c)
+++ src/routes/posts.js	(revision f1e0c1fd1bed6e546d243788f1c217d74f043dad)
@@ -365,4 +365,10 @@
     if (post.status !== 'published') ActivityPubService.deliverCreate(site, apPost).catch(() => { /* best-effort */ });
     else ActivityPubService.deliverUpdate(site, apPost).catch(() => { /* best-effort */ });
+  }
+
+  // Pin/unpin changed → push an actor Update so Mastodon re-fetches the featured
+  // (pinned) collection promptly instead of waiting for its own actor refresh.
+  if ((post.pinned || 0) !== parsePinnedRank(pinned)) {
+    ActivityPubService.deliverActorUpdate(site).catch(() => { /* best-effort */ });
   }
 
Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision 75bda38ace3a3eff7e9ea9d7676a2ad33a8ad24c)
+++ src/services/ActivityPubService.js	(revision f1e0c1fd1bed6e546d243788f1c217d74f043dad)
@@ -651,4 +651,24 @@
     type: 'Update', actor: me, to: [PUBLIC], cc: [`${me}/followers`],
     object: note,
+  };
+  for (const inbox of inboxes) deliverWithRetry(site.slug, inbox, update, `${me}#main-key`, keys.private_pem);
+}
+
+// Tell followers the ACTOR changed (Update + Person) so Mastodon re-processes the
+// account AND re-fetches the featured (pinned) collection — there is no standard
+// "featured changed" activity, so this is how a pin/unpin propagates promptly.
+export async function deliverActorUpdate(site) {
+  const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, '');
+  if (!base || !site || !site.slug) return;
+  const followers = fStmts().list.all(site.slug);
+  if (!followers.length) return;
+  const inboxes = [...new Set(followers.map((f) => f.shared_inbox || f.inbox).filter(Boolean))];
+  const keys = getOrCreateKeys(site.slug);
+  const me = actorId(base, site.slug);
+  const update = {
+    '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'],
+    id: `${me}#update-${Date.now()}`,
+    type: 'Update', actor: me, to: [PUBLIC], cc: [`${me}/followers`],
+    object: buildActor(base, site),
   };
   for (const inbox of inboxes) deliverWithRetry(site.slug, inbox, update, `${me}#main-key`, keys.private_pem);
@@ -985,5 +1005,5 @@
   getOrCreateKeys, apWants, sendAP, actorId, noteId,
   buildActor, buildNote, buildCreate, buildOutbox, buildFollowers, buildFeatured,
-  followerCount, deliver, fetchActor, verifyRequest, handleInbox, deliverCreate, deliverDelete, deliverUpdate,
+  followerCount, deliver, fetchActor, verifyRequest, handleInbox, deliverCreate, deliverDelete, deliverUpdate, deliverActorUpdate,
   getInteractions, getInteractionById, buildReplyNote, getOutboxNote, deliverReply, resolveRemoteNote,
   listOutbox, deliverOutboxDelete,
