OnlyFans API Webhooks: Complete Integration Guide for Real-Time Events
Article Summary
Master webhook integration with OnlyFans API. Learn how to receive real-time events, handle subscriber updates, and build event-driven creator platforms.
OnlyFans API Webhooks: Complete Integration Guide for Real-Time Events
Building responsive creator platforms requires real-time data synchronization. OnlyFans API webhooks enable your application to receive instant notifications about subscriber events, new messages, revenue updates, and more. This comprehensive guide covers everything you need to implement robust webhook integration with oFANS API.
Understanding OnlyFans API Webhooks
Webhooks are HTTP callbacks that deliver real-time event data to your application. Instead of constantly polling the OnlyFans API for updates, webhooks push notifications directly to your server when events occur. This architecture reduces API calls, improves performance, and enables instant user experiences.
Why Use Webhooks with OnlyFans API?
Implementing OnlyFans API webhooks provides significant advantages:
- Instant notifications for new subscribers, messages, and revenue
- Reduced API calls by up to 90% compared to polling
- Better user experience with real-time updates
- Lower infrastructure costs through efficient resource usage
- Scalable architecture that grows with your platform
To get started with OnlyFans API webhooks, sign up for API access and enable webhook notifications in your dashboard.
Webhook Event Types
The OnlyFans API sends webhooks for various creator events:
Subscriber Events
subscriber.new - Triggered when a creator gains a new subscriber:
{ "event": "subscriber.new", "timestamp": "2024-12-03T10:30:00.000Z", "data": { "subscriber_id": "12345678", "username": "fan_username", "subscription_type": "monthly", "price": 9.99, "trial": false, "source": "profile" } }
subscriber.renewed - Triggered when a subscription renews:
{ "event": "subscriber.renewed", "timestamp": "2024-12-03T10:35:00.000Z", "data": { "subscriber_id": "12345678", "username": "fan_username", "renewal_count": 3, "price": 9.99 } }
subscriber.expired - Triggered when a subscription ends:
{ "event": "subscriber.expired", "timestamp": "2024-12-03T10:40:00.000Z", "data": { "subscriber_id": "12345678", "username": "fan_username", "total_months": 6, "lifetime_value": 59.94 } }
Message Events
message.received - New message from a subscriber:
{ "event": "message.received", "timestamp": "2024-12-03T11:00:00.000Z", "data": { "message_id": "msg_987654", "from_user_id": "12345678", "username": "fan_username", "text": "Love your content!", "has_media": false } }
Revenue Events
revenue.received - New payment or tip received:
{ "event": "revenue.received", "timestamp": "2024-12-03T11:15:00.000Z", "data": { "transaction_id": "txn_123456", "user_id": "12345678", "amount": 25.00, "type": "tip", "message": "Keep up the great work!" } }
Setting Up Your Webhook Endpoint
Creating the Webhook Handler
First, create a secure endpoint to receive OnlyFans API webhooks:
const express = require('express'); const crypto = require('crypto'); const app = express(); app.use(express.json()); app.post('/webhooks/onlyfans', async (req, res) => { try { // Verify webhook signature const signature = req.headers['x-webhook-signature']; if (!verifyWebhookSignature(req.body, signature)) { return res.status(401).json({ error: 'Invalid signature' }); } const event = req.body; // Process event asynchronously await handleWebhookEvent(event); // Always respond quickly (within 5 seconds) res.status(200).json({ received: true }); } catch (error) { console.error('Webhook processing error:', error); res.status(500).json({ error: 'Internal server error' }); } }); app.listen(3000, () => { console.log('Webhook server running on port 3000'); });
Webhook Signature Verification
Secure your webhook endpoint by verifying signatures:
const verifyWebhookSignature = (payload, signature) => { const webhookSecret = process.env.ONLYFANS_WEBHOOK_SECRET; // Compute expected signature const hmac = crypto.createHmac('sha256', webhookSecret); const payloadString = JSON.stringify(payload); hmac.update(payloadString); const expectedSignature = hmac.digest('hex'); // Compare signatures using timing-safe comparison return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSignature) ); };
Environment Configuration
Store webhook credentials securely:
# .env ONLYFANS_API_KEY=sk_live_your_key_here ONLYFANS_WEBHOOK_SECRET=whsec_your_secret_here WEBHOOK_URL=https://yourdomain.com/webhooks/onlyfans
Processing Webhook Events
Event Router Pattern
Implement a clean event routing system:
const handleWebhookEvent = async (event) => { const { event: eventType, timestamp, data } = event; // Log all events for debugging console.log(`Webhook received: ${eventType}`, { timestamp, dataKeys: Object.keys(data) }); // Route to appropriate handler switch(eventType) { case 'subscriber.new': await handleNewSubscriber(data); break; case 'subscriber.renewed': await handleSubscriberRenewal(data); break; case 'subscriber.expired': await handleSubscriberExpiry(data); break; case 'message.received': await handleNewMessage(data); break; case 'revenue.received': await handleRevenueEvent(data); break; case 'post.published': await handleNewPost(data); break; default: console.log(`Unknown event type: ${eventType}`); } };
New Subscriber Handler
Process new subscriber events with OnlyFans API webhooks:
const handleNewSubscriber = async (data) => { const { subscriber_id, username, subscription_type, trial } = data; // Store in database await db.subscribers.create({ subscriberId: subscriber_id, username: username, type: subscription_type, isTrial: trial, subscribedAt: new Date(), status: 'active' }); // Send welcome message via OnlyFans API await sendWelcomeMessage(subscriber_id, username); // Update analytics await updateSubscriberMetrics('new', 1); // Trigger business logic if (!trial) { await addToEmailCampaign(subscriber_id); } // Notify team await sendSlackNotification(`New subscriber: ${username}`); }; const sendWelcomeMessage = async (subscriberId, username) => { const welcomeText = `Hey ${username}! Welcome to my page. Thanks for subscribing!`; const response = await fetch('https://app.ofans-api.com/api/chat/send', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.ONLYFANS_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ user_id: subscriberId, text: welcomeText }) }); return await response.json(); };
Database Integration
Storing Webhook Events
Create a robust event storage system:
const storeWebhookEvent = async (event) => { await db.webhook_events.insert({ event_id: generateEventId(), event_type: event.event, timestamp: new Date(event.timestamp), payload: event.data, processed: false, created_at: new Date() }); }; const handleWebhookEvent = async (event) => { // Store event first await storeWebhookEvent(event); try { // Process event await processEvent(event); // Mark as processed await db.webhook_events.update({ event_id: event.id, processed: true, processed_at: new Date() }); } catch (error) { // Log error but don't fail webhook receipt await db.webhook_errors.insert({ event_id: event.id, error: error.message, stack: error.stack, retry_count: 0 }); } };
Event Deduplication
Prevent duplicate event processing:
const processedEvents = new Set(); const isDuplicateEvent = async (eventId) => { // Check in-memory cache first if (processedEvents.has(eventId)) { return true; } // Check database const existing = await db.webhook_events.findOne({ event_id: eventId, processed: true }); if (existing) { processedEvents.add(eventId); return true; } return false; }; const handleWebhookEvent = async (event) => { const eventId = event.id || generateEventId(event); if (await isDuplicateEvent(eventId)) { console.log('Duplicate event detected, skipping'); return; } processedEvents.add(eventId); await processEvent(event); };
Advanced Webhook Patterns
Asynchronous Processing
Handle webhooks asynchronously for better performance:
const Queue = require('bull'); const webhookQueue = new Queue('webhooks', { redis: { host: process.env.REDIS_HOST, port: process.env.REDIS_PORT } }); app.post('/webhooks/onlyfans', async (req, res) => { // Verify signature if (!verifyWebhookSignature(req.body, req.headers['x-webhook-signature'])) { return res.status(401).json({ error: 'Invalid signature' }); } // Queue for processing await webhookQueue.add('process', req.body, { attempts: 3, backoff: { type: 'exponential', delay: 2000 } }); // Respond immediately res.status(200).json({ received: true }); }); // Worker process webhookQueue.process('process', async (job) => { const event = job.data; await handleWebhookEvent(event); });
Retry Logic
Implement intelligent retry mechanisms:
const processWithRetry = async (event, maxRetries = 3) => { for (let attempt = 1; attempt <= maxRetries; attempt++) { try { await processEvent(event); return { success: true, attempts: attempt }; } catch (error) { console.error(`Attempt ${attempt} failed:`, error.message); if (attempt === maxRetries) { // Final attempt failed await logFailedEvent(event, error); throw error; } // Exponential backoff const delay = Math.pow(2, attempt) * 1000; await sleep(delay); } } }; const logFailedEvent = async (event, error) => { await db.failed_webhooks.insert({ event_type: event.event, payload: event.data, error: error.message, retry_count: 3, failed_at: new Date() }); // Alert team await sendAlertEmail(`Webhook processing failed: ${event.event}`); };
Real-Time Analytics with Webhooks
Building Live Dashboards
Create real-time analytics using OnlyFans API webhooks. Learn more about building analytics dashboards.
const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 8080 }); // Store connected clients const clients = new Map(); wss.on('connection', (ws, req) => { const creatorId = req.url.split('?creatorId=')[1]; clients.set(creatorId, ws); console.log(`Dashboard connected for creator: ${creatorId}`); }); // Push webhook events to connected dashboards const handleNewSubscriber = async (data) => { const creatorId = data.creator_id; // Store in database await db.subscribers.create(data); // Push to connected dashboard const client = clients.get(creatorId); if (client && client.readyState === WebSocket.OPEN) { client.send(JSON.stringify({ type: 'subscriber_update', action: 'new', data: { username: data.username, timestamp: new Date().toISOString(), total: await getSubscriberCount(creatorId) } })); } };
Revenue Tracking
Track revenue in real-time with webhooks:
const handleRevenueEvent = async (data) => { const { transaction_id, user_id, amount, type } = data; // Store transaction await db.transactions.create({ transactionId: transaction_id, userId: user_id, amount: amount, type: type, timestamp: new Date() }); // Update daily revenue cache const today = new Date().toISOString().split('T')[0]; await redis.hincrby(`revenue:${today}`, type, amount); // Check for milestones const totalToday = await getTodayRevenue(); if (totalToday >= 1000 && totalToday - amount < 1000) { await sendMilestoneNotification('$1,000 daily revenue milestone reached!'); } // Push to dashboard await broadcastRevenueUpdate({ amount, type, total: totalToday }); };
Webhook Security Best Practices
IP Whitelisting
Restrict webhook access to trusted IPs:
const OFANS_API_IPS = [ '52.89.214.238', '34.212.75.30', // Add actual oFANS API webhook IPs ]; const verifyWebhookIP = (req, res, next) => { const clientIP = req.ip || req.connection.remoteAddress; if (!OFANS_API_IPS.includes(clientIP)) { console.warn(`Webhook request from unauthorized IP: ${clientIP}`); return res.status(403).json({ error: 'Forbidden' }); } next(); }; app.post('/webhooks/onlyfans', verifyWebhookIP, async (req, res) => { // Handle webhook });
Rate Limiting Webhooks
Protect against webhook flooding:
const rateLimit = require('express-rate-limit'); const webhookLimiter = rateLimit({ windowMs: 60 * 1000, // 1 minute max: 100, // Max 100 webhooks per minute message: 'Too many webhook requests', standardHeaders: true }); app.post('/webhooks/onlyfans', webhookLimiter, async (req, res) => { // Handle webhook });
HTTPS Requirement
Always use HTTPS for webhook endpoints:
const https = require('https'); const fs = require('fs'); const options = { key: fs.readFileSync('./ssl/private-key.pem'), cert: fs.readFileSync('./ssl/certificate.pem') }; const server = https.createServer(options, app); server.listen(443, () => { console.log('Secure webhook server running on port 443'); });
Testing Webhooks Locally
Using ngrok for Local Development
Expose your local server for webhook testing:
# Install ngrok npm install -g ngrok # Start your local server node server.js # Expose port 3000 ngrok http 3000
Copy the ngrok URL (e.g., https://abc123.ngrok.io) and configure it in your oFANS API dashboard webhook settings.
Webhook Testing Tool
Create a testing utility:
const testWebhook = async (eventType) => { const testPayloads = { 'subscriber.new': { event: 'subscriber.new', timestamp: new Date().toISOString(), data: { subscriber_id: 'test_12345', username: 'test_user', subscription_type: 'monthly', price: 9.99, trial: false } } // Add other test payloads }; const payload = testPayloads[eventType]; // Generate signature const signature = generateSignature(payload); // Send to local webhook const response = await fetch('http://localhost:3000/webhooks/onlyfans', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Webhook-Signature': signature }, body: JSON.stringify(payload) }); console.log('Test webhook response:', await response.json()); }; // Run test testWebhook('subscriber.new');
Monitoring Webhook Health
Tracking Webhook Metrics
Monitor webhook performance:
const metrics = { received: 0, processed: 0, failed: 0, averageProcessingTime: 0 }; const trackWebhookMetrics = async (event, processingTime, success) => { metrics.received++; if (success) { metrics.processed++; } else { metrics.failed++; } // Update average processing time metrics.averageProcessingTime = (metrics.averageProcessingTime * (metrics.processed - 1) + processingTime) / metrics.processed; // Store in database await db.webhook_metrics.insert({ event_type: event.event, processing_time: processingTime, success: success, timestamp: new Date() }); }; const handleWebhookEvent = async (event) => { const startTime = Date.now(); let success = false; try { await processEvent(event); success = true; } catch (error) { console.error('Event processing failed:', error); } finally { const processingTime = Date.now() - startTime; await trackWebhookMetrics(event, processingTime, success); } };
Health Check Endpoint
Implement webhook health monitoring:
app.get('/webhooks/health', async (req, res) => { const health = { status: 'healthy', uptime: process.uptime(), metrics: { last_hour: await getWebhookStats('1h'), last_24h: await getWebhookStats('24h'), failure_rate: (metrics.failed / metrics.received) * 100 }, timestamp: new Date().toISOString() }; res.json(health); }); const getWebhookStats = async (timeRange) => { const since = timeRange === '1h' ? new Date(Date.now() - 60 * 60 * 1000) : new Date(Date.now() - 24 * 60 * 60 * 1000); const events = await db.webhook_events.find({ created_at: { $gte: since } }); return { total: events.length, successful: events.filter(e => e.processed).length, failed: events.filter(e => !e.processed).length }; };
Scaling Webhook Processing
Horizontal Scaling
Scale webhook handlers across multiple servers:
const cluster = require('cluster'); const numCPUs = require('os').cpus().length; if (cluster.isMaster) { console.log(`Master process ${process.pid} starting`); // Fork workers for (let i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', (worker) => { console.log(`Worker ${worker.process.pid} died, starting new worker`); cluster.fork(); }); } else { // Worker processes handle webhooks const app = createWebhookServer(); app.listen(3000, () => { console.log(`Worker ${process.pid} listening on port 3000`); }); }
Load Balancing
Distribute webhook load with nginx:
upstream webhook_servers { least_conn; server webhook1.yourdomain.com:3000; server webhook2.yourdomain.com:3000; server webhook3.yourdomain.com:3000; } server { listen 443 ssl http2; server_name webhooks.yourdomain.com; ssl_certificate /etc/ssl/certs/cert.pem; ssl_certificate_key /etc/ssl/private/key.pem; location /webhooks/onlyfans { proxy_pass http://webhook_servers; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # Increase timeouts for webhook processing proxy_connect_timeout 10s; proxy_send_timeout 10s; proxy_read_timeout 10s; } }
Integrating with Chat Automation
Combine webhooks with chat automation for powerful workflows. Check our guide on OnlyFans chat automation best practices for more details.
const handleNewMessage = async (data) => { const { message_id, from_user_id, text, username } = data; // Store message await db.messages.create({ messageId: message_id, userId: from_user_id, text: text, receivedAt: new Date() }); // Check if automated response needed if (shouldAutoRespond(text)) { const response = await generateAIResponse(text, from_user_id); await sendMessage(from_user_id, response); } else { // Flag for human review await flagForReview(message_id, 'manual_response_needed'); } // Update engagement metrics await updateEngagementStats(from_user_id); }; const shouldAutoRespond = (text) => { const autoRespondKeywords = ['hi', 'hello', 'hey', 'thanks']; const lowerText = text.toLowerCase(); return autoRespondKeywords.some(keyword => lowerText.includes(keyword)); };
Error Handling and Debugging
Webhook Logging
Implement comprehensive logging:
const winston = require('winston'); const webhookLogger = winston.createLogger({ level: 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.json() ), transports: [ new winston.transports.File({ filename: 'webhooks-error.log', level: 'error' }), new winston.transports.File({ filename: 'webhooks-combined.log' }) ] }); const handleWebhookEvent = async (event) => { webhookLogger.info('Webhook received', { event_type: event.event, timestamp: event.timestamp, data_keys: Object.keys(event.data) }); try { await processEvent(event); webhookLogger.info('Webhook processed successfully', { event_type: event.event, event_id: event.id }); } catch (error) { webhookLogger.error('Webhook processing failed', { event_type: event.event, error: error.message, stack: error.stack }); throw error; } };
Debugging Failed Webhooks
Create a webhook replay system:
const replayFailedWebhook = async (eventId) => { const event = await db.webhook_events.findOne({ event_id: eventId }); if (!event) { throw new Error(`Event ${eventId} not found`); } console.log(`Replaying webhook event: ${eventId}`); try { await processEvent({ event: event.event_type, data: event.payload, timestamp: event.timestamp }); await db.webhook_events.update({ event_id: eventId, processed: true, replayed: true, replayed_at: new Date() }); console.log(`Successfully replayed event: ${eventId}`); } catch (error) { console.error(`Replay failed for event ${eventId}:`, error); throw error; } }; // CLI tool for replaying failed webhooks // node replay-webhook.js <event_id> if (require.main === module) { const eventId = process.argv[2]; replayFailedWebhook(eventId) .then(() => process.exit(0)) .catch(err => { console.error(err); process.exit(1); }); }
Production Deployment
Kubernetes Configuration
Deploy webhook handlers with Kubernetes:
apiVersion: apps/v1 kind: Deployment metadata: name: webhook-handler spec: replicas: 3 selector: matchLabels: app: webhook-handler template: metadata: labels: app: webhook-handler spec: containers: - name: webhook image: your-registry/webhook-handler:latest ports: - containerPort: 3000 env: - name: ONLYFANS_API_KEY valueFrom: secretKeyRef: name: api-secrets key: api-key - name: ONLYFANS_WEBHOOK_SECRET valueFrom: secretKeyRef: name: api-secrets key: webhook-secret resources: requests: memory: "128Mi" cpu: "100m" limits: memory: "256Mi" cpu: "200m" --- apiVersion: v1 kind: Service metadata: name: webhook-handler spec: selector: app: webhook-handler ports: - protocol: TCP port: 80 targetPort: 3000 type: LoadBalancer
Docker Configuration
Containerize your webhook handler:
FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . EXPOSE 3000 CMD ["node", "webhook-server.js"]
Best Practices Summary
Do's
- Always verify webhook signatures before processing
- Respond within 5 seconds to avoid timeouts
- Process events asynchronously for better performance
- Implement idempotency to handle duplicate events
- Log all webhook events for debugging and auditing
- Monitor webhook health with metrics and alerts
- Use HTTPS for all webhook endpoints
- Implement retry logic with exponential backoff
- Store raw webhook payloads for replay capability
- Test thoroughly before production deployment
Don'ts
- Don't process synchronously in the webhook handler
- Don't expose sensitive data in webhook responses
- Don't skip signature verification (security risk)
- Don't make long-running API calls in the handler
- Don't ignore failed events without proper logging
- Don't use HTTP for webhook endpoints (use HTTPS)
- Don't process duplicate events without deduplication
Related Resources
Expand your OnlyFans API integration knowledge:
- Complete OnlyFans API Integration Guide
- Building Analytics Dashboards
- Revenue Optimization Strategies
- Scaling Your Platform
Get Started with Webhooks Today
Ready to implement OnlyFans API webhooks? Sign up for oFANS API and enable real-time event notifications in your dashboard. Our team provides dedicated support to help you integrate webhooks successfully.
oFANS API delivers webhooks with 99.95% reliability and sub-second latency. Start building event-driven creator platforms today.
For technical support and webhook configuration assistance, check our documentation or join our Telegram community.
Build real-time creator platforms with oFANS API webhooks. Trusted by 105+ agencies worldwide for reliable event delivery and comprehensive developer support.
Ready to start building with OnlyFans API?
Join 105+ agencies using oFANS API to build powerful creator tools and platforms.
Related Articles
Complete OnlyFans API Integration Guide 2025: Step-by-Step Tutorial
Learn how to integrate OnlyFans API into your application with this comprehensive step-by-step guide. Perfect for developers building creator management tools.
Building OnlyFans Analytics Dashboard with API: Complete Guide
Create powerful analytics dashboards for OnlyFans creators using oFANS API. Learn how to track metrics, visualize data, and provide actionable insights.
OnlyFans Chat Automation Best Practices: AI-Powered Guide 2025
Master OnlyFans chat automation with AI. Learn best practices, implementation strategies, and how to scale your messaging with oFANS API.