Aller au contenu
Développeurs

Webhooks de communauté

Mateflow envoie une requête HTTP POST à votre URL quand quelque chose se passe dans une communauté. Cette page décrit ce que reçoit votre récepteur, comment le vérifier, ce qui se passe en cas d’échec, et chaque champ de chaque événement.

Démarrage rapide

Chaque livraison est un POST avec un corps JSON. Si plusieurs webhooks sont abonnés à un événement, chacun reçoit sa propre copie.

  1. Dans l’administration de votre communauté, ouvrez Paramètres → Intégrations → Webhooks et créez un webhook : saisissez l’URL, choisissez les événements, générez un secret et activez-le.
  2. Traitez chaque requête dans cet ordre :
    1. Lisez le corps brut de la requête et vérifiez la signature.
    2. Si test vaut true, renvoyez 200 et arrêtez-vous.
    3. Dédupliquez sur event_id.
    4. Placez le travail dans votre propre file d’attente et renvoyez un 2xx en moins de 10 secondes.
  3. Cliquez sur Tester le webhook pour envoyer une requête de test, puis ouvrez Journaux de livraison pour voir la requête et la réponse.

Offres et configuration

Les webhooks sont une fonctionnalité d’offre, et seuls les administrateurs de la communauté peuvent les gérer.

OffreWebhooks par communauté
FreeNon disponible
StarterNon disponible
Growth5
Business20
EnterpriseIllimité
  • Après un passage à une offre sans webhooks, vos réglages de webhook sont conservés, mais rien n’est livré ni journalisé. Repasser à une offre supérieure rétablit la livraison.
  • Les webhooks se créent et se gèrent dans la console d’administration. L’Open API de la communauté n’a aucun endpoint pour eux.

Configuration

RéglageExigence
URLLe formulaire d’administration n’accepte que les URL en https://, jusqu’à 1 024 caractères.
Adresses inaccessiblesLes requêtes vers des adresses qui se résolvent en plages de bouclage (loopback), privées ou de lien local sont bloquées au moment de la connexion et traitées comme une erreur réseau. Pour le développement local, utilisez un tunnel public.
NomJusqu’à 100 caractères.
ÉvénementsAu moins un, parmi le catalogue ci-dessous. Un webhook enregistré auparavant avec une liste d’événements vide reçoit tous les événements.
SecretFacultatif, jusqu’à 128 caractères. Une fois enregistré, il peut être remplacé mais pas relu. Sans secret, les requêtes ne sont pas signées ; nous recommandons donc vivement d’en définir un. Le secret lui-même n’apparaît jamais dans une requête.

Format de livraison

Chaque livraison est un POST avec un délai d’expiration de 10 secondes par requête.

En-têtes

En-têteValeurRemarques
Content-Typeapplication/jsonToujours du JSON.
User-AgentMateflow-Webhook/1.0Identifie Mateflow comme l’expéditeur.
X-Mateflow-TimestampSecondes UnixMoment où cette requête a été envoyée. Fait partie de la signature.
X-Mateflow-Signaturesha256= suivi d’un condensé hexadécimalPrésent uniquement si le webhook a un secret.

Les webhooks personnalisés n’ont pas d’en-tête X-Mateflow-Delivery-Id. Lisez delivery_id dans le corps.

Corps

ChampTypeDescription
eventstringLe code de l’événement.
event_idstringL’identifiant unique de l’événement. Dédupliquez sur ce champ. Il reste identique d’une nouvelle tentative automatique à l’autre, lors des renvois manuels, et pour tous les webhooks abonnés à l’événement. Traitez-le comme une chaîne opaque.
occurred_atRFC 3339Moment où l’événement s’est produit, à la seconde près. Il reste identique d’une nouvelle tentative à l’autre.
delivery_idstring (décimal)Identifie cette livraison. Il change à chaque nouvelle tentative automatique ; un renvoi manuel conserve la valeur d’origine.
timestampRFC 3339Moment où le corps a été généré. Un renvoi manuel conserve la valeur d’origine : utilisez donc l’en-tête pour juger de la fraîcheur.
webhook_idhashidLe webhook qui reçoit cette livraison.
site_idhashidLa communauté.
dataobjectLes données de l’événement, décrites dans le catalogue des événements.

Dans de rares cas, lorsque la génération des identifiants échoue, event_id et occurred_at peuvent être absents. Acceptez-le, et repliez-vous sur event associé à l’identifiant métier présent dans data pour repérer les doublons.

JSON
{
  "event": "payment.received",
  "event_id": "86116692152877061",
  "occurred_at": "2026-11-03T00:00:00Z",
  "delivery_id": "86116692152877060",
  "timestamp": "2026-11-03T00:00:01Z",
  "webhook_id": "qP3aXm71Bd",
  "site_id": "Z5Kf08mFv8r",
  "data": {
    "member_id": "b7Lq2WxR9e",
    "username": "sample_member",
    "email": "sample.member@example.com",
    "invoice_id": "in_1Abc",
    "subscription_id": "sub_1Abc",
    "amount_cents": 2900,
    "currency": "usd",
    "period_start": "2026-11-03T00:00:00Z",
    "period_end": "2026-12-03T00:00:00Z"
  }
}

Vérifier les signatures

Quand un webhook a un secret, chaque requête est signée avec HMAC-SHA256 sur l’en-tête d’horodatage et le corps brut.

Signature
X-Mateflow-Signature = "sha256=" + hex(
  HMAC-SHA256(secret, X-Mateflow-Timestamp + "." + raw_request_body)
)
  • Utilisez les octets bruts. Les caractères spéciaux en HTML peuvent être échappés dans le corps ; analyser le JSON puis le resérialiser produit donc d’autres octets, et la signature ne correspondra pas.
  • Prenez l’horodatage dans l’en-tête, pas dans le corps. Un renvoi manuel ne met à jour que l’horodatage de l’en-tête et la signature.
  • Une vérification de l’horodatage n’interfère pas avec les nouvelles tentatives. Chaque nouvelle tentative automatique et chaque renvoi manuel est signé à nouveau : une fenêtre de 5 minutes suffit.
Node.js
const crypto = require('crypto');

// rawBody must be the untouched bytes, e.g. from express.raw({ type: 'application/json' }).
function verifyMateflowSignature(rawBody, headers, secret, toleranceSeconds = 300) {
  const timestamp = headers['x-mateflow-timestamp'];
  const received = headers['x-mateflow-signature'] || '';
  if (!timestamp || Math.abs(Date.now() / 1000 - Number(timestamp)) > toleranceSeconds) {
    return false;
  }
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.`)
    .update(rawBody)
    .digest('hex');
  const a = Buffer.from(received);
  const b = Buffer.from(expected);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Python
import hashlib
import hmac
import time


def verify_mateflow_signature(raw_body: bytes, headers, secret: str, tolerance_seconds: int = 300) -> bool:
    timestamp = headers.get("X-Mateflow-Timestamp", "")
    received = headers.get("X-Mateflow-Signature", "")
    if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > tolerance_seconds:
        return False
    signed = timestamp.encode() + b"." + raw_body
    expected = "sha256=" + hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return hmac.compare_digest(received.encode(), expected.encode())

Vecteur de test

Utilisez ces valeurs pour vérifier votre calcul de signature. L’horodatage a expiré : assouplissez donc votre fenêtre de temps pendant les tests.

Vecteur de test
secret                 my_signing_secret
X-Mateflow-Timestamp   1793664000
raw body (UTF-8)       {"event":"member.joined","data":{"username":"张三"}}
X-Mateflow-Signature   sha256=3f4c83828ce0086150c9bd48c1654899357b7c05265c1d1b6c172225ee04b4b4

Changer de secret

Un nouveau secret prend effet dès qu’il est enregistré, et les nouvelles tentatives en attente sont elles aussi signées avec lui. Il n’existe aucune période où Mateflow signe avec les deux ; faites donc accepter à votre récepteur l’ancien et le nouveau secret pendant la transition.

Réponses et nouvelles tentatives

Le jugement porté sur une livraison dépend uniquement de votre code de statut. Le corps de la réponse n’est pas analysé.

Votre récepteurRésultatNouvelle tentative
2xxSuccèsNon
5xx, 408, 429ÉchecOui
Délai dépassé, échec de connexion, adresse bloquéeÉchec, journalisé avec le statut 0Oui
Tout autre 4xxÉchecNon
  • Calendrier des nouvelles tentatives : après un échec, Mateflow attend 1 minute, 10 minutes, 1 heure, puis 6 heures. Avec la première tentative, cela fait au plus 5 tentatives sur environ 7 heures.
  • Quand la livraison est abandonnée : une fois les nouvelles tentatives épuisées, ou sur un statut qui n’est pas retenté, le propriétaire et les administrateurs de la communauté reçoivent un e-mail, au plus un par webhook toutes les 24 heures.
  • Arrêt en cours de route : si le webhook est supprimé ou désactivé, ou si l’offre n’inclut plus les webhooks, les tentatives suivantes ne sont ni envoyées ni journalisées.
  • Redirections : les livraisons suivent les redirections, mais un 301, 302 ou 303 transforme le POST en GET sans corps. Saisissez l’URL finale, et ne comptez pas sur une redirection de http vers https.

Renvoi manuel

Renvoyer dans Journaux de livraison renvoie une livraison à l’URL actuelle du webhook.

  • Le corps est identique, y compris event_id, delivery_id et timestamp. L’en-tête d’horodatage et la signature sont nouveaux.
  • Il n’y a qu’une seule tentative, sans nouvelle tentative en cas d’échec. Le résultat apparaît comme une nouvelle ligne dans le journal.
  • Seules les livraisons de webhooks personnalisés peuvent être renvoyées, et le webhook doit toujours exister et être activé.

Journaux de livraison

Les journaux sont conservés 30 jours. Seuls les 4 premiers Ko du corps de chaque réponse sont enregistrés.

Fiabilité

Ce que votre récepteur peut et ne peut pas supposer.

  • Au moins une fois. Un même événement peut arriver plusieurs fois. Dédupliquez sur event_id.
  • Ajoutez un second contrôle pour tout ce qui touche à l’argent. Mateflow dédoublonne déjà un même paiement et un même début ou une même fin d’abonnement, mais si cette vérification est indisponible, il envoie plutôt que d’abandonner, et les deux événements ont alors des valeurs de event_id différentes. Vérifiez aussi invoice_id, subscription_id ou order_id.
  • Aucune garantie d’ordre. Les livraisons s’exécutent en parallèle et sont retentées ; access_group_removed et access_group_added d’un membre peuvent donc arriver inversés. Pour déterminer lequel est venu en premier, utilisez occurred_at, précis à la seconde.
  • Une perte rare est possible. Les événements sont mis en file après la validation des données ; un processus qui s’arrête entre ces deux étapes perd donc l’événement.
  • Réconciliez si vous synchronisez un état. Considérez un événement comme un signal qu’un changement a eu lieu, lisez l’état actuel depuis l’Open API (par exemple /member/get avec la portée members.read), et lancez périodiquement une comparaison complète. L’Open API ne renvoie pas les adresses e-mail : prenez-les dans les événements.

Catalogue des événements

Vous pouvez vous abonner à 17 événements.

Règles valables pour chaque champ

  • Les identifiants Mateflow sont des chaînes hashid, les mêmes valeurs que dans l’API. La valeur 0 n’est pas encodée et apparaît comme le nombre 0.
  • member_id et user_id désignent la même personne. member.joined, les événements de publication et les événements de commentaire utilisent user_id ; tout le reste utilise member_id.
  • Les identifiants Stripe sont transmis tels quels : invoice_id, subscription_id, charge_id et payment_intent_id.
  • Les heures sont en RFC 3339, en UTC.
  • Les montants sont des entiers dans la plus petite unité de la devise (centimes pour l’USD), et currency est un code de devise en minuscules.
  • Un champ facultatif qui ne s’applique pas est omis. Ce n’est ni null ni une chaîne vide.
  • Des champs et des valeurs d’énumération sont ajoutés, jamais modifiés. Votre récepteur doit tolérer les nouveaux.

Tous les événements

ÉvénementSignificationNom d’utilisateur et e-mail
member.joinedUn nouveau membre a rejoint la communautéOui
member.leftUn membre a quitté la communautéOui
member.role_changedLe rôle d’un membre a changéNon
member.suspendedUn membre a été suspendu ou banniNon
member.reinstatedUne suspension ou un bannissement a été levéNon
member.access_group_addedUn membre a commencé à appartenir à un groupe d’accèsOui
member.access_group_removedUn membre a cessé d’appartenir à un groupe d’accèsOui
post.createdUne publication a été publiéeNon
post.deletedUne publication a été suppriméeNon
comment.createdUn commentaire a été publiéNon
comment.deletedUn commentaire a été suppriméNon
payment.receivedUn paiement est arrivé, pour une facture d’abonnement ou un achat uniqueOui
subscription.renewedUn abonnement a été renouvelé avec succèsOui
payment.failedLe paiement d’une facture a échouéOui
subscription.createdUn abonnement a été créé dans StripeOui
subscription.canceledUn abonnement a pris finOui
refund.issuedUn remboursement a été émisOui

Membres

member.joined

Un nouveau membre a rejoint la communauté.

ChampTypeToujours présentDescription
user_idhashidOuiIdentifiant du membre.
usernamestringOuiNom d’utilisateur.
emailstringOuiAdresse e-mail.

Envoyé quand

  • Une inscription réussit, y compris par connexion sociale, une première connexion SSO ou une inscription via une invitation.
  • Une inscription payante est terminée.
  • Une demande d’adhésion est approuvée.
  • Quelqu’un s’inscrit de nouveau avec la même adresse e-mail et son compte est restauré. L’événement est renvoyé.

Non envoyé quand

  • Des membres sont importés depuis un fichier CSV.
  • Un membre attend encore son approbation dans une communauté qui examine les demandes d’adhésion.

member.left

Un membre a quitté la communauté.

ChampTypeToujours présentDescription
member_idhashidOuiLa même valeur que le user_id du membre dans member.joined.
usernamestringOuiNom d’utilisateur avant le départ, même si le départ efface ses données personnelles.
emailstringOuiAdresse e-mail avant le départ, dans les mêmes conditions.
sourcestringOuiComment la personne est partie. Voir le tableau ci-dessous.
removed_byhashidNonL’administrateur qui a agi. Uniquement pour removed et anonymized.
reasonstringNonUniquement pour removed, quand l’administrateur a donné un motif.
sourceSignificationNouvelle inscription avec la même adresse e-mail
removedUn administrateur a retiré le membreRestaure le même identifiant et renvoie member.joined
account_deletedLe membre a supprimé son propre compte, immédiatement ou à la fin du délai de réflexion de 30 joursSuppression immédiate : comme ci-dessus. Après le délai de réflexion : un nouvel identifiant
anonymizedUn administrateur a anonymisé le membre au titre du GDPR (RGPD)Un nouvel identifiant
inactivityNettoyage des comptes inactifs, exécuté par lots nocturnesUn nouvel identifiant

Non envoyé quand

  • Un compte est désactivé.
  • Un membre est dans le délai de réflexion après avoir demandé la suppression de son compte. L’événement est envoyé à la fin du délai, et pas du tout s’il annule.
  • Un membre est banni ou suspendu, ce qui envoie member.suspended.
  • Quelqu’un n’a jamais rejoint la communauté, par exemple une demande d’adhésion refusée ou en attente.
  • Un abonnement prend fin.
  • La communauté est supprimée.
  • Un membre quitte un seul espace.
  • Les groupes d’accès effacés par le départ ne sont pas envoyés un par un sous la forme member.access_group_removed. Considérez member.left comme signifiant que le membre n’appartient plus à aucun groupe d’accès.

member.role_changed

Le rôle d’un membre a changé.

ChampTypeToujours présentDescription
member_idhashidOuiIdentifiant du membre.
previous_rolestringOuimember, moderator ou admin, toujours en minuscules.
rolestringOuiLes mêmes valeurs.
changed_byhashidOuiQui a effectué le changement.

Non envoyé quand

  • Le rôle n’a pas réellement changé.
  • Seul Administrateur de facturation ou un rôle personnalisé a changé.

member.suspended

Un membre a été suspendu ou banni. Les deux utilisent cet événement, distingués par ban_type.

ChampTypeToujours présentDescription
member_idhashidOuiIdentifiant du membre.
suspended_byhashidOuiL’administrateur qui a agi.
reasonstringOuiLa note interne de l’administrateur. Peut être une chaîne vide. Ne la montrez pas au membre.
ban_typestringOuisuspend ou ban.
duration_daysnumberNonUniquement pour suspend.
suspended_untilRFC 3339NonUniquement pour suspend.
viastringNonmoderation quand l’action a eu lieu lors du traitement d’un signalement. Omis quand elle a été faite depuis la gestion des membres.

Envoyé quand

  • Un membre est suspendu ou banni depuis la gestion des membres ou lors du traitement d’un signalement, individuellement ou en masse.

Non envoyé quand

  • Un membre reçoit seulement un avertissement.

member.reinstated

Une suspension ou un bannissement a été levé.

ChampTypeToujours présentDescription
member_idhashidOuiIdentifiant du membre.
reinstated_byhashidNonL’administrateur qui a agi. Omis quand via vaut expired.
fromstringOuiCe qui a été levé : suspend ou ban.
viastringNonmoderation (levé en modération), appeal (appel accepté) ou expired (la suspension est arrivée à terme). Omis quand la levée a été faite depuis la gestion des membres.

Non envoyé quand

  • Une suspension est arrivée à terme, mais le membre a un autre bannissement actif et reste donc restreint.
  • Quand une suspension arrive à terme, l’événement part en général dans les quelques minutes, car les expirations sont vérifiées toutes les 5 minutes. occurred_at correspond au moment où l’expiration a été constatée.

member.access_group_added, member.access_group_removed

Un membre a commencé ou cessé d’appartenir à un groupe d’accès. Chaque événement concerne un membre et un groupe d’accès ; passer un abonnement de Silver à Gold envoie donc un removed et un added.

ChampTypeToujours présentDescription
member_idhashidOuiIdentifiant du membre.
usernamestringOuiNom d’utilisateur.
emailstringOuiAdresse e-mail.
access_group_idhashidOuiLa même valeur que access_groups[].id dans l’Open API.
access_group_namestringOuiLe nom du groupe à ce moment-là. Pour un groupe supprimé, le nom avant suppression.
sourcestringOuiVoir le tableau ci-dessous.
changed_byhashidNonUniquement pour manual et invitation.
sourceÉvénementsSignificationchanged_by
manualadded, removedUn administrateur l’a accordé ou retiré dans la consoleL’administrateur
subscriptionadded, removedUn abonnement a commencé, pris fin ou changé de niveauAucun
invitationaddedLe membre a accepté une invitationLa personne qui a invité
defaultaddedLe membre est entré dans le groupe par défautAucun
group_deletedremovedLe groupe d’accès a été suppriméAucun

Non envoyé quand

  • L’ensemble des groupes du membre n’a pas réellement changé.
  • Un membre entre automatiquement dans le groupe par défaut à l’inscription.
  • Le changement concerne un membre qui attend encore son approbation.
  • Les groupes sont effacés parce que le compte a été supprimé.
  • Supprimer un groupe d’accès ou définir un groupe par défaut est un changement en masse. Les événements sont envoyés membre par membre et arrivent de quelques secondes à quelques minutes après l’action, tandis que occurred_at reste l’heure de l’action. Leur event_id a un format différent, c’est pourquoi il doit être traité comme opaque.

Contenu

Dans les quatre événements, post_id est l’identifiant du contenu lui-même et user_id est l’auteur, et non la personne qui a agi. space_id est omis quand le contenu n’est pas dans un espace. Le contenu des espaces privés est lui aussi envoyé : filtrez donc sur space_id si votre récepteur en a besoin.

post.created

Une publication ou un article de blog a été publié.

ChampTypeToujours présentDescription
post_idhashidOuiIdentifiant de la publication.
user_idhashidOuiL’auteur.
space_idhashidNonL’espace qui la contient.
titlestringOuiTitre. Peut être une chaîne vide.
bodystringOuiSource Markdown, jusqu’à 500 caractères. Elle peut être coupée plus tôt à un mot ou à un signe de ponctuation, sans points de suspension. Pour un article de blog, c’est l’extrait.

Envoyé quand

  • Une publication ou un article de blog devient public : il est publié directement, approuvé depuis la file de modération, ou atteint son heure programmée.

Non envoyé quand

  • Un commentaire est publié, ce qui envoie comment.created.
  • Un article de blog envoie cet événement à la première publication seulement, mais un article dépublié puis reprogrammé peut l’envoyer de nouveau. Rendez votre traitement idempotent sur post_id.

post.deleted

Une publication ou un article de blog a été supprimé.

ChampTypeToujours présentDescription
post_idhashidOuiIdentifiant de la publication.
user_idhashidOuiL’auteur.
space_idhashidNonL’espace qui la contient.

Envoyé quand

  • L’auteur le supprime, un administrateur le supprime (individuellement ou en masse), il est retiré lors du traitement d’un signalement, ou un bannissement efface le contenu du membre. Effacer le contenu d’un membre peut produire un lot d’événements.

Non envoyé quand

  • Un article de blog est dépublié et repasse en brouillon, ce qui n’est pas une suppression.
  • Supprimer une publication programmée qui n’a jamais été publiée envoie aussi cet événement ; le recevoir ne signifie donc pas que vous avez reçu post.created auparavant.
  • Il n’existe pas d’événement distinct pour la restauration d’un contenu.

comment.created

Un commentaire a été publié.

ChampTypeToujours présentDescription
post_idhashidOuiL’identifiant propre du commentaire.
parent_idhashidOuiLa publication ou le commentaire auquel on répond.
user_idhashidOuiL’auteur.
space_idhashidNonL’espace qui la contient.
bodystringOuiLes mêmes règles que body dans post.created.

comment.deleted

Un commentaire a été supprimé. Il est envoyé dans les mêmes conditions que post.deleted.

ChampTypeToujours présentDescription
post_idhashidOuiL’identifiant propre du commentaire.
parent_idhashidOuiLa publication ou le commentaire auquel on répond.
user_idhashidOuiL’auteur.
space_idhashidNonL’espace qui la contient.

Paiements et abonnements

Ces événements couvrent les abonnements Stripe, les achats uniques d’espaces et les remboursements. Ils portent username et email, sauf si le membre n’existe plus.

Les achats intégrés à l’application et les abonnements offerts en cadeau ou obtenus par un code d’échange n’envoient ni payment.* ni subscription.*. Si l’offre est liée à un groupe d’accès, ils envoient member.access_group_added avec source défini sur subscription, puis member.access_group_removed quand l’accès prend fin, ce que vous pouvez utiliser pour suivre les changements de droits d’accès.

Lors d’une inscription payante, le paiement précède le compte ; les événements du premier paiement sont donc envoyés une fois le compte créé : member.joined, subscription.created, et payment.received si la première facture est payée. Ils peuvent arriver dans n’importe quel ordre.

payment.received

Un paiement est arrivé. Il existe deux formes de charge utile, que vous distinguez selon que invoice_id est présent ou non.

ChampTypeFacture d’abonnementAchat uniqueDescription
member_idhashidOuiOuiIdentifiant du membre.
usernamestringEn généralEn généralOmis si le membre n’existe plus.
emailstringEn généralEn généralOmis si le membre n’existe plus.
amount_centsnumberOuiOuiLe montant payé. 0 pour la facture à montant nul au début d’un essai.
currencystringOuiOuiDevise.
invoice_idstringOuiNonIdentifiant de la facture Stripe.
subscription_idstringOuiNonIdentifiant de l’abonnement Stripe.
period_startRFC 3339OuiNonDébut de la période achetée par ce paiement.
period_endRFC 3339OuiNonFin de la période achetée par ce paiement. Vous pouvez l’utiliser comme date d’expiration de l’accès.
order_idhashidNonOuiIdentifiant de la commande.
space_idhashidNonOuiL’espace acheté.
payment_intent_idstringNonOuiIdentifiant du PaymentIntent Stripe.
  • L’événement n’a pas de plan_id.
  • Un achat unique envoie cet événement une fois l’accès accordé, une fois par commande.

subscription.renewed

Un abonnement a été renouvelé avec succès. Les champs sont les mêmes que ceux de la forme facture d’abonnement de payment.received.

  • Un renouvellement envoie les deux événements, avec des valeurs de event_id différentes. Si vous vous abonnez aux deux, n’enregistrez pas le revenu deux fois.

payment.failed

Le paiement d’une facture a échoué. Il est envoyé à chaque échec, y compris chaque fois que Stripe retente le prélèvement.

ChampTypeToujours présentDescription
member_idhashidOuiIdentifiant du membre.
usernamestringNonOmis si le membre n’existe plus.
emailstringNonOmis si le membre n’existe plus.
invoice_idstringOuiIdentifiant de la facture Stripe.
subscription_idstringOuiIdentifiant de l’abonnement Stripe.
amount_due_centsnumberOuiLe montant dû.
currencystringOuiDevise.
attempt_countnumberOuiLe numéro de cette tentative pour la facture.

subscription.created

Un abonnement a été créé dans Stripe. Cela ne signifie pas qu’il a été payé ; utilisez payment.received pour cela.

ChampTypeToujours présentDescription
member_idhashidOuiIdentifiant du membre.
usernamestringNonOmis si le membre n’existe plus.
emailstringNonOmis si le membre n’existe plus.
subscription_idstringOuiIdentifiant de l’abonnement Stripe.
plan_idhashidOuiL’identifiant de l’offre d’abonnement des membres.
statusstringOuiValeurs courantes : active, trialing et incomplete (première facture non réglée).
price_centsnumberOuiLe prix unitaire de l’offre, avant remises.
currencystringOuiDevise.
billing_periodstringOuimonthly ou annual.
period_startRFC 3339OuiDébut de la période en cours.
period_endRFC 3339OuiFin de la période en cours.

subscription.canceled

Un abonnement a réellement pris fin. Un membre qui programme l’annulation à la fin de la période ne l’envoie pas ; la fin de la période, si.

ChampTypeToujours présentDescription
member_idhashidOuiIdentifiant du membre.
usernamestringNonOmis si le membre n’existe plus.
emailstringNonOmis si le membre n’existe plus.
subscription_idstringOuiIdentifiant de l’abonnement Stripe.
plan_idhashidOuiL’identifiant de l’offre d’abonnement des membres.
previous_statusstringOuiLe statut avant la fin, comme active, trialing ou past_due.
cancelled_atRFC 3339OuiMoment où il a pris fin.
  • Un abonnement qui expire sans avoir jamais été payé envoie aussi cet événement, avec previous_status défini sur incomplete. Ce membre n’a jamais eu accès : ne le comptez pas comme un départ (churn).
  • L’orthographe est incohérente : l’événement s’écrit canceled, le champ cancelled_at, et la valeur de statut de l’abonnement cancelled.

refund.issued

Un remboursement a été émis. Les remboursements de factures d’abonnement et d’achats uniques partagent cet événement avec des champs différents. Vous les distinguez selon que invoice_id est présent ou non.

ChampTypeFacture d’abonnementAchat uniqueDescription
member_idhashidOuiOuiIdentifiant du membre.
usernamestringEn généralEn généralOmis si le membre n’existe plus.
emailstringEn généralEn généralOmis si le membre n’existe plus.
amount_refunded_centsnumberOuiOuiLe total remboursé jusqu’ici, et non le montant de ce remboursement.
currencystringOuiOuiDevise.
refund_statusstringrefunded ou partially_refundedrefundedLe statut après le remboursement.
is_partialbooleanOuiToujours falseIndique s’il s’agit d’un remboursement partiel.
previous_statusstringPar exemple paid ou partially_refundedcompletedLe statut avant le remboursement.
invoice_idstringOuiNonIdentifiant de la facture Stripe.
charge_idstringOui, peut être une chaîne videUniquement pour les remboursements lancés dans StripeIdentifiant du paiement (charge) Stripe.
order_idhashidNonOuiIdentifiant de la commande.
space_idhashidNonOuiL’espace acheté.
payment_intent_idstringNonOuiIdentifiant du PaymentIntent Stripe.
  • Un remboursement partiel d’un achat unique effectué dans Stripe n’envoie aucun événement, et la commande et l’accès restent inchangés.

Livraisons de test

Tester le webhook dans la console d’administration envoie une requête immédiatement et écrit le résultat dans le journal de livraison. Un webhook désactivé peut aussi être testé, et il n’y a pas de nouvelle tentative. Le format est le même que celui d’une vraie livraison, signature comprise, sauf pour les points suivants.

ÉlémentLivraison de testVraie livraison
testtrueAbsent
eventToujours member.joined, quels que soient les événements auxquels le webhook est abonnéL’événement auquel on est abonné
dataDonnées d’exempleDonnées réelles
event_id, occurred_atAbsentsPrésents

Vérifiez test en premier et renvoyez 200 quand il vaut true. Sinon, un test de member.joined pourrait réellement créer un membre dans votre système.

Autres canaux

Journaux de livraison affiche aussi ces sources. Elles utilisent les mêmes événements que les webhooks personnalisés, dans des formats différents.

CanalCorpsSignatureAutres différences
ZapierLes mêmes data. L’enveloppe ajoute un booléen test et n’a pas de webhook_id.Uniquement si un secret de signature a été défini lors de la connexion. Même algorithme.Ajoute un en-tête X-Mateflow-Delivery-Id.
Slack, DiscordDu texte lisible uniquement, sous text pour Slack et content pour Discord.Comme pour Zapier.Ajoute un en-tête X-Mateflow-Delivery-Id. Aucun champ structuré.
Règle d’automatisation : Déclencher un webhookLe modèle écrit dans la règle.Uniquement si la règle a un secret. Même algorithme.N’utilise pas cette enveloppe. La règle décide du moment de l’envoi.
Rappelez votre communauté avec l’Open API

Commencez à construire

Créez un webhook dans la console d’administration de votre communauté, envoyez une livraison de test et vérifiez-la dans les journaux.

Essai gratuit de 14 jours · Puis Free jusqu’à 100 membres · Sans carte bancaire