Skip to main content
Webhooks are a way for your app to receive live notifications of activity on your user’s accounts. Currently we support 6 different event types:
  • Message Received
  • Message Read
  • New Follower
  • New Subscriber
  • Purchase Received
  • Tip Received

Setting up a webhook

  1. Set up an endpoint on your backend to receive webhooks. It should accept POST requests from our API and return a 2xx response.
  2. Navigate to the Fanvue Developer Area, select your app and open the Events tab. Events tab
  3. Click Add Webhook. In the dialog, enter your Endpoint URL and select the events you want this endpoint to receive. Use Select All to subscribe to every event, or tick individual events. A single endpoint can listen for multiple events. Add Webhook dialog
  4. Click Save. The webhook is created and appears in the Events & Endpoints list, where you can enable or disable it with the toggle.
Each webhook event requires certain OAuth scopes to work. Enable the required scopes in the Authentication tab. See Required scopes per event for the full mapping.

Missing scope warnings

Different webhook events require different OAuth scopes. For an event to be delivered, your app must have the scopes that event needs enabled in the Authentication tab, under Define permissions. If a webhook needs scopes that your app does not yet have, the Events tab shows a warning that the required consents are missing. Enable the relevant scopes in the Authentication tab to clear it. Authentication permissions Note that adding a scope to your app is not enough on its own for already-connected users: creators who authorized your app before the scope was added must re-authorize it before those events will be delivered. See Re-authorize the app after scope changes.

Managing and testing webhooks

Each webhook in the Events & Endpoints list has an actions () menu:
  • Edit, change the endpoint URL or the events it subscribes to.
  • Test, send a sample payload to your endpoint so you can confirm it is reachable and that your signature verification works, without waiting for a real user action.
  • History, review recent delivery attempts for the webhook.
  • Delete, remove the webhook.
Webhook actions menu

How deliveries work

  • Each webhook is delivered as an HTTP POST with Content-Type: application/json.
  • The request body contains an event-specific JSON payload.
  • Your endpoint should return a 2xx response as soon as you successfully receive and persist the event.

Verifying webhook signatures

Every webhook request includes an X-Fanvue-Signature header (format t=<timestamp>,v0=<signature>). Verify it on every request so forged or replayed events are rejected before you act on them. See Verify Webhook Signatures for the header breakdown, where to find your signing secret, the step-by-step verification flow, and complete Node and Python samples.

Testing locally

  • Expose your local server with a tunneling tool (for example, ngrok) and copy the public HTTPS URL.
  • Add a webhook in the Events tab with that URL and the events you want to receive.
  • Use the Test action in the webhook’s menu to send a sample payload to your endpoint, or trigger the event in a test environment, then inspect the request reaching your server.

Troubleshooting: test events work, but production events do not

If webhook test deliveries succeed but real user activity does not trigger events, use this checklist.

1) Confirm required OAuth scopes are enabled for each event

Webhook eventRequired scope
follow.newread:creator
purchase.newread:creator
subscription.newread:creator
tip.newread:creator
message.receivedread:chat
message.readread:chat
creator.logoutread:self

2) Confirm the webhook event checkbox is enabled

In your app’s Webhooks tab, verify the event type is selected for the webhook endpoint you configured.

3) Re-authorize the app after scope changes

If scopes were added after users already connected your app, previously granted consent may not include those scopes yet.
  1. Open https://fanvue.com/settings/account/third-party-apps
  2. Revoke access for your app
  3. Reconnect the app and approve the requested scopes again

4) Validate with a real production action

Use an actual follow, purchase, subscription, tip, or message event from a separate account and verify delivery on your endpoint logs.

Example endpoint (Node.js / Express)

import crypto from "crypto";
import express from "express";

const app = express();

const SIGNING_SECRET = process.env.FANVUE_WEBHOOK_SECRET!;
const TOLERANCE_SECONDS = 300; // 5 minutes

function verifyWebhookSignature(payload: string, signatureHeader: string): boolean {
  const parts = signatureHeader.split(",");
  let timestamp: string | undefined;
  let signature: string | undefined;

  for (const part of parts) {
    const [key, value] = part.split("=");
    if (key === "t") timestamp = value;
    if (key === "v0") signature = value;
  }

  if (!timestamp || !signature) return false;

  const currentTime = Math.floor(Date.now() / 1000);
  if (Math.abs(currentTime - parseInt(timestamp, 10)) > TOLERANCE_SECONDS) {
    return false;
  }

  const signedPayload = `${timestamp}.${payload}`;
  const expectedSignature = crypto
    .createHmac("sha256", SIGNING_SECRET)
    .update(signedPayload)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// Use raw body for signature verification
app.use(
  express.json({
    verify: (req: any, _res, buf) => {
      req.rawBody = buf.toString();
    },
  })
);

app.post("/webhooks/fanvue", (req: any, res) => {
  const signatureHeader = req.headers["x-fanvue-signature"];

  if (!signatureHeader || !verifyWebhookSignature(req.rawBody, signatureHeader)) {
    res.status(401).json({ error: "Invalid signature" });
    return;
  }

  const event = req.body;
  // Process the event...

  res.sendStatus(200);
});

app.listen(3000);