Index: src/routes/activitypub.js
===================================================================
--- src/routes/activitypub.js	(revision 6bd25d164a42c0ff47b98ae2f2e006233dcd5efa)
+++ src/routes/activitypub.js	(revision 5bf63b70700b4f2b8855d87b6e8b5cc11fd5e801)
@@ -80,9 +80,13 @@
 });
 
-// ── Inbox (Phase 1 stub: accept; Follow/Accept + sig verify next step) ──
-const apJson = express.json({ type: ['application/activity+json', 'application/ld+json', 'application/json'], limit: '1mb' });
-router.post(['/ap/users/:slug/inbox', '/ap/inbox'], apJson, (req, res) => {
-  try { console.log('[AP inbox]', (req.body && req.body.type) || 'unknown', '→', req.params.slug || 'shared'); } catch { /* ignore */ }
-  res.status(202).end();
+// ── Inbox — Follow→Accept, Undo Follow (best-effort signature verify) ──
+const apJson = express.json({
+  type: ['application/activity+json', 'application/ld+json', 'application/json'],
+  limit: '1mb',
+  verify: (req, _res, buf) => { req.rawBody = buf; }, // raw body for digest verification
+});
+router.post(['/ap/users/:slug/inbox', '/ap/inbox'], apJson, async (req, res) => {
+  try { return res.status(await AP.handleInbox(req, req.params.slug || null) || 202).end(); }
+  catch (e) { console.warn('[AP inbox] error:', e.message); return res.status(202).end(); }
 });
 
