ofapisv1
info

OnlyFans Webhook Setup

This is a practical, step-by-step OnlyFans webhook setup guide using ofapis, so your app reacts to events in real time instead of polling on a timer. You'll register an endpoint, verify signatures, handle events safely, and confirm delivery. Budget about ten minutes.

Step 1 — Stand up an HTTPS endpoint

Webhooks require a public HTTPS URL that returns quickly. A minimal receiver:

from flask import Flask, request

app = Flask(__name__)

@app.post("/webhooks/ofapis")
def receive():
    raw = request.get_data()  # keep the RAW bytes
    sig = request.headers.get("X-Ofapis-Signature", "")
    if not verify(raw, sig, SIGNING_SECRET):
        return "", 400
    event = request.get_json()
    enqueue(event)            # do work async
    return "", 200            # ack fast

Return 2xx fast and push the real work onto a queue — slow handlers get retried and can pile up.

Step 2 — Register the endpoint

In the dashboard, add the endpoint URL (HTTPS only) and subscribe it to events. message.received is live today. On creation you get a signing secret — a random base64url string — shown once; store it like any other credential. This is the same flow described in OnlyFans webhooks.

Step 3 — Verify the signature

Every request carries X-Ofapis-Signature: t=<timestamp>,v1=<hex>. Compute HMAC-SHA256 over <timestamp>.<raw_body> with your secret, compare in constant time, and reject stale timestamps to block replays:

import hmac, hashlib, time

def verify(raw, header, secret, tolerance=300):
    parts = dict(p.split("=", 1) for p in header.split(","))
    ts, v1 = parts["t"], parts["v1"]
    if abs(time.time() - int(ts)) > tolerance:
        return False
    signed = f"{ts}.".encode() + raw
    expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, v1)

Always verify against the raw body bytes, before any JSON parsing or framework re-serialization mutates them.

Step 4 — Handle events idempotently

Delivery is at-least-once, so a retry reuses the same event id. Deduplicate on it before acting:

def enqueue(event):
    if seen(event["id"]):     # already processed? drop it
        return
    if event["type"] == "message.received":
        auto_reply(event["account_id"], event["data"])

The payload is a stable envelope — id, type, created, account_id, and a scoped data object. Pair message.received with the messaging API to auto-reply, or feed it into a chatbot.

Step 5 — Confirm and monitor

Send a test event and watch it land. The dashboard shows delivered, retrying, and failed counts per endpoint; failed deliveries are retried with exponential backoff, so a brief outage self-heals. Common gotchas:

Symptom Likely cause
Signature never matches Verifying parsed JSON, not raw bytes
Random 400s after a while Timestamp tolerance too tight / clock skew
Duplicate replies sent No dedupe on event id
Deliveries marked failed Handler too slow — ack first, work async

Webhook deliveries don't cost credits; only your outbound API calls are metered. For the event catalog and payload details, see webhook events explained.

FAQ

What do I need before setting up an OnlyFans webhook?

A public HTTPS endpoint that returns 2xx quickly, a connected OnlyFans account, and the signing secret from the dashboard. That's enough to register an endpoint and start receiving message.received events.

How do I verify a webhook is really from ofapis?

Compute HMAC-SHA256 over <timestamp>.<raw_body> with your signing secret and compare it, in constant time, to the v1 value in the X-Ofapis-Signature header. Reject anything that doesn't match or whose timestamp is stale.

Why must I use the raw request body?

JSON parsing and framework re-serialization can reorder keys or change whitespace, which changes the bytes the signature was computed over. Verify against the untouched raw body first, then parse.

What happens if my endpoint is temporarily down?

ofapis retries failed deliveries with exponential backoff and shows retrying and failed counts in the dashboard. Because retries reuse the same event id, deduplicate so you don't process an event twice.

OnlyFans webhooks reference · Webhook events explained · Messaging API · Docs · Start free

Related guides

All guides
Start free — 250 credits, no card
Generate a token and make your first call in minutes.
Get started