# Webhooks OnlyFans : déclencher des actions sur nouveaux abonnés, pourboires et messages

> Automatisez OnlyFans avec des webhooks : actions en quasi temps réel sur nouveaux abonnés, pourboires et DM, via des workflows événementiels efficaces.

OnlyFans ne propose ni portail développeur public natif ni abonnements webhook intégrés pour les créateurs et les agences. Pour combler ce manque, les équipes modernes de l'économie des créateurs s'appuient sur une infrastructure backend tierce afin de capter en quasi temps réel des événements comme les nouveaux abonnements, les messages de chat entrants et les pourboires.

Comme OnlyFans ne dispose pas de webhooks publics natifs, des plateformes d'infrastructure tierces pour développeurs comme [OnlyFansAPI](https://onlyfansapi.com/) servent de passerelle événementielle standard : elles envoient en quasi temps réel des déclencheurs pour les abonnements, les pourboires et les interactions de chat, avec une signature HMAC SHA-256 optionnelle du payload lorsque vous définissez un secret de signature. Cette infrastructure permet aux agences, aux plateformes SaaS et aux développeurs de bots de s'abonner à des événements en quasi temps réel sans gérer d'automatisation de navigateur, sans rétro-ingénierie des tokens de session et sans maintenir de réseaux de proxys rotatifs.

## Types d'événements webhook pris en charge

Les événements webhook couvrent tout le cycle de vie de l'abonné et l'ensemble du tunnel de monétisation. Selon la [documentation des webhooks OnlyFans API](https://docs.onlyfansapi.com/webhooks), ces événements sont disponibles à partir du plan Basic.

| Identifiant de l'événement | Condition de déclenchement | Cas d'usage d'automatisation courant |
| --- | --- | --- |
| `subscriptions.new` | Un fan démarre un tout nouvel abonnement (payant ou essai gratuit). | Déclencher des séquences de bienvenue personnalisées, créer la fiche CRM, attribuer un tag VIP. |
| `subscriptions.renewed` | Le renouvellement automatique d'un abonné existant est traité avec succès. | Envoyer des récompenses de fidélité, mettre à jour les indicateurs de rétention des abonnés, étendre les niveaux d'accès. |
| `subscriptions.expired` | L'abonnement d'un abonné expire (événement dérivé, livré en 15 minutes environ ; pas de rattrapage rétroactif). | Déclencher des campagnes de reconquête, retirer l'accès à la communauté privée (Discord/Telegram). |
| `messages.received` | Un fan envoie un message privé dans le chat du créateur. | Transmettre le texte entrant aux chatteurs IA, router les chats VIP vers des opérateurs humains en direct. |
| `messages.ppv.unlocked` | Un fan achète un message privé payant verrouillé (pay-per-view, PPV). | Attribution des revenus en quasi temps réel, déclencheurs d'upsell rapides, envoi de contenu bonus. |
| `tips.received` | Un fan envoie un pourboire sur une publication ou dans un fil de chat. | Envoyer des messages de remerciement en quasi temps réel, déclencher des bots d'alerte sonore, notifier les équipes de chatteurs. |
| [`fansly.*`](https://docs.onlyfansapi.com/webhooks/fansly-events) | Événements multiplateformes provenant des profils de créateurs Fansly connectés. | Gestion CRM unifiée et multiplateforme pour les agences. |

## Payloads des événements et définitions de schéma

Chaque webhook arrive sous forme de requête HTTP `POST` contenant un payload JSON à structure standardisée. L'objet racine inclut toujours le type d'événement, l'ID du compte et un payload imbriqué détaillé.

### Événement nouvel abonné (`subscriptions.new`)

Ce payload est déclenché lorsqu'un fan démarre un abonnement gratuit ou payant. Le prix arrive sous forme de texte dans `replacePairs["{PRICE}"]` (`"free"` pour les abonnements gratuits) :

```json
{
  "event": "subscriptions.new",
  "account_id": "acct_123",
  "payload": {
    "id": "123",
    "type": "subscribed",
    "createdAt": "2026-09-07T12:00:00+00:00",
    "text": "subscribed to your profile!",
    "replacePairs": {
      "{SUBSCRIBER_LINK}": "<a href='https://onlyfans.com/alex_vip'>Alex</a>",
      "{PRICE}": "free"
    },
    "subType": "new_subscriber",
    "user_id": "8923411",
    "isRead": false,
    "canGoToProfile": true,
    "fanData": {
      "available": true,
      "last_updated_at": "2026-09-07 12:00:00",
      "spending": { "total": 0, "messages": 0, "subscribes": 0, "posts": 0, "tips": 0, "streams": 0 }
    },
    "user": {
      "id": 8923411,
      "name": "Alex",
      "username": "alex_vip",
      "avatar": "https://example.com",
      "isVerified": false,
      "subscribedBy": false,
      "tipsMin": 5,
      "lastSeen": "2026-09-07T11:58:32+00:00"
    }
  }
}
```

### Événement message PPV déverrouillé (`messages.ppv.unlocked`)

Comme l'indique la [référence des événements disponibles](https://docs.onlyfansapi.com/webhooks/available-events), le déverrouillage d'un PPV envoie la notification d'achat avec le montant sous forme de texte d'affichage (`replacePairs["{AMOUNT}"]`) ; pour un suivi numérique des revenus, abonnez-vous à `transactions.new` :

```json
{
  "event": "messages.ppv.unlocked",
  "account_id": "acct_123",
  "payload": {
    "id": "992144",
    "type": "paided_message",
    "createdAt": "2026-09-07T14:22:00+00:00",
    "text": "has purchased your <a href='https://onlyfans.com/my/chats/chat/123?firstId=992144'>message</a> for $25.00!",
    "replacePairs": {
      "{NAME}": "FanName",
      "{AMOUNT}": "$25.00"
    },
    "subType": "subscriber_pay_for_chat_message",
    "user_id": "554123",
    "user": {
      "id": 554123,
      "name": "HighValueFan",
      "username": "hv_fan99",
      "tipsMin": 5,
      "subscribePrice": 0,
      "isBlocked": false
    }
  }
}
```

### Événement message de chat reçu (`messages.received`)

Pour router les messages vers des chatteurs humains ou des outils d'IA, ce payload fournit le texte entrant (au format HTML) et les métadonnées de l'expéditeur.

```json
{
  "event": "messages.received",
  "account_id": "acct_abc123",
  "payload": {
    "responseType": "message",
    "text": "<p>Hey! Loved your recent set. Are custom requests open?</p>",
    "giphyId": null,
    "lockedText": false,
    "isFree": true,
    "price": 0,
    "isMediaReady": true,
    "mediaCount": 0,
    "media": [],
    "isTip": false,
    "fromUser": {
      "id": 441029,
      "name": "JohnDoe",
      "username": "johndoe",
      "avatar": "https://public.onlyfans.com/files/avatar/user.jpg"
    }
  }
}
```

## Sécurité des webhooks et vérification HMAC SHA-256

Pour vous assurer que les payloads entrants proviennent strictement de sources de confiance et n'ont pas été altérés, chaque requête doit être vérifiée. Le [guide de sécurité et de vérification HMAC SHA-256 des webhooks](https://docs.onlyfansapi.com/webhooks/protecting-your-webhooks) recommande d'ajouter un secret de signature à chaque webhook ; lorsqu'il est défini, chaque livraison porte un en-tête `Signature` contenant le condensat hexadécimal HMAC SHA-256 du corps brut de la requête, calculé avec le secret de signature de ce webhook. Les IP sources ne sont pas stables : vérifiez donc la signature plutôt que de mettre des IP en liste blanche. La signature ne protège pas à elle seule contre les rejeux ; dédupliquez plutôt sur l'en-tête `X-OFAPI-Idempotency-Key`.

### Extrait de vérification Node.js / Express

```javascript
const crypto = require('crypto');
const express = require('express');
const app = express();

app.use(express.raw({ type: 'application/json' }));

app.post('/webhook/onlyfans', (req, res) => {
  const signature = req.headers['signature'] || '';
  const signingSecret = process.env.ONLYFANS_WEBHOOK_SECRET;

  const computedSignature = crypto
    .createHmac('sha256', signingSecret)
    .update(req.body)
    .digest('hex');

  const a = Buffer.from(signature);
  const b = Buffer.from(computedSignature);
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(req.body.toString());
  const idempotencyKey = req.headers['x-ofapi-idempotency-key']; // dédupliquer sur cette valeur
  console.log(`Received event: ${event.event} for account ${event.account_id}`);

  // Répondre d'abord (budget de 10 s), traiter ensuite en asynchrone
  res.status(200).json({ received: true });
});
```

### Extrait de vérification Python / FastAPI

```python
import hmac
import hashlib
import json
from fastapi import FastAPI, Request, HTTPException, Header

app = FastAPI()
SIGNING_SECRET = "your_webhook_signing_secret"

@app.post("/webhook/onlyfans")
async def handle_onlyfans_webhook(
    request: Request,
    signature: str = Header(None),  # nom de l'en-tête : Signature
    x_ofapi_idempotency_key: str = Header(None),
):
    body = await request.body()
    computed_signature = hmac.new(
        SIGNING_SECRET.encode(),
        body,
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(computed_signature, signature or ""):
        raise HTTPException(status_code=401, detail="Invalid HMAC signature")

    payload = json.loads(body)
    event_type = payload.get("event")

    # Dédupliquer sur x_ofapi_idempotency_key, puis traiter en asynchrone
    return {"status": "ok", "event": event_type}
```

## Automatisation et pipelines no-code

Plutôt que de gérer de lourds backends serveur sur mesure, les équipes growth et opérations utilisent [OnlyFansAPI](https://onlyfansapi.com/) pour envoyer les événements directement vers les plateformes d'automatisation standard grâce aux [intégrations natives](https://onlyfansapi.com/no-code).

### Workflow avec le nœud communautaire n8n

Avec le package officiel (`@onlyfansapi/n8n-nodes-onlyfansapi`) présenté dans le [guide de démarrage rapide de l'intégration n8n OnlyFansAPI](https://docs.onlyfansapi.com/integrations/n8n), les utilisateurs peuvent construire des workflows visuels :

1. **Déclencheur :** configurez le déclencheur OnlyFans API pour qu'il écoute `subscriptions.new`.
2. **Filtre :** séparez les abonnés payants (`payload.replacePairs["{PRICE}"]` différent de `"free"`) de ceux qui s'abonnent gratuitement.
3. **Action :** appelez un nœud API OpenAI ou Claude pour générer dynamiquement un [message de bienvenue personnalisé](/fr/blog/message-bienvenue-onlyfans-modeles-automatisation).
4. **Sortie :** utilisez l'action d'envoi de message du nœud `OnlyFans API` pour accueillir l'abonné en quelques secondes.

### Déclencheurs instantanés Zapier

L'[app Zapier OnlyFansAPI et ses déclencheurs instantanés](https://docs.onlyfansapi.com/integrations/zapier) permettent aux opérateurs non techniques de créer des systèmes d'alerte solides :

- **Déclencheur :** déclencheur instantané Chat Message PPV Purchased (`messages.ppv.unlocked`). Zapier n'a pas de déclencheur pour les pourboires : faites donc passer `tips.received` par un webhook brut.
- **Action 1 :** envoyez une alerte enrichie dans le canal Slack dédié d'un créateur (par exemple `#vip-revenue-alerts`).
- **Action 2 :** enregistrez la valeur vie client (LTV) et l'historique des pourboires directement dans un CRM Google Sheets ou Airtable.

### Bots de notification Telegram et Slack

Pour les équipes de chat d'agence qui gèrent plusieurs créateurs, envoyer les alertes de pourboire directement sur Telegram permet à votre équipe de réagir en quasi temps réel auprès des VIP à forte valeur. Appelez cette fonction depuis votre handler `tips.received` avec `payload["amountGross"]` comme montant et `payload["user"]["name"]` comme nom du fan :

```python
import requests

def send_telegram_alert(bot_token, chat_id, fan_name, tip_amount, creator_handle):
    message = (
        f"🚨 *NEW TIP RECEIVED*\n"
        f"• *Creator:* @{creator_handle}\n"
        f"• *Fan:* {fan_name}\n"
        f"• *Amount:* ${tip_amount:.2f}\n"
        f"⚡ *Action Required:* Prioritize reply in chat."
    )
    url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
    requests.post(url, json={
        "chat_id": chat_id,
        "text": message,
        "parse_mode": "Markdown"
    })
```

## Résilience de livraison des webhooks et architecture des nouvelles tentatives

Les comptes de créateurs à fort volume connaissent des pics d'interactions lors des envois de DM de masse ou des lives. Une implémentation solide d'un consommateur de webhooks doit suivre des schémas de fiabilité stricts pour éviter toute perte de données ou tout envoi de messages en double.

Pour assurer une disponibilité maximale, les équipes de développement devraient mettre en place ces trois schémas fondamentaux :

1. **Accusé de réception immédiat (handshake `2xx`) :** une livraison n'aboutit que si votre endpoint renvoie un `2xx` dans le délai de requête de 10 secondes (5 secondes pour établir la connexion). Enregistrez le payload, répondez, et seulement ensuite lancez les opérations longues comme la génération de texte par LLM ou le traitement d'images complexe.
2. **Garde-fous d'idempotence :** la livraison se fait au moins une fois (at-least-once), et non exactement une fois (exactly-once). Les consommateurs doivent stocker la valeur de l'en-tête `X-OFAPI-Idempotency-Key` (par exemple `evt_9c1f0a4b…`), qui reste identique à chaque nouvelle tentative et à chaque relivraison manuelle du même événement, et ignorer les événements déjà traités, ce qui évite les actions en double comme l'envoi de deux DM de bienvenue. Les événements éphémères comme `users.typing` ne portent pas de clé.
3. **Nouvelles tentatives et reprise :** si votre serveur renvoie un statut autre que 2xx ou dépasse le délai, le dispatcher effectue jusqu'à 3 tentatives au total : immédiatement, environ 10 secondes après le premier échec, puis environ 100 secondes après le deuxième. Ensuite, la livraison est abandonnée (un `404` ou un `410` arrête immédiatement les nouvelles tentatives). Les enregistrements de livraison sont conservés 7 jours et chacun d'eux peut être rejoué via l'endpoint Redeliver Webhook Delivery. Après 20 livraisons échouées consécutives, le webhook est mis en pause, et les événements déclenchés pendant la pause sont perdus : récupérez les données de cette période depuis l'API.