Index: src/routes/admin-paid.js
===================================================================
--- src/routes/admin-paid.js	(revision 61e3daf1227ad67cd38c4a5e9e79cfeb1ea92121)
+++ src/routes/admin-paid.js	(revision 603d2461f6fb57f0422bea17aad09eef157f788f)
@@ -18,4 +18,10 @@
 const router = express.Router();
 
+// The redirect URI the owner MUST whitelist in their Patreon client. Must match
+// exactly what paid.js sends, or Patreon shows its own error page (which we
+// cannot skin) instead of returning the visitor to us.
+const redirectUri = (req) =>
+  (process.env.PUBLIC_BASE_URL || `${req.protocol}://${req.get('host')}`).replace(/\/+$/, '') + '/paid/callback';
+
 function gate(req, res) {
   if (!premiumUnlocked()) {
@@ -34,4 +40,5 @@
     status: PaidPatreon.ownerStatus(res.locals.site.id),
     secretReady: cryptoBoxReady(),
+    redirectUri: redirectUri(req),
     saved: req.query.saved === '1',
     error: req.query.error || null,
