Webhooks pour les paiements

Mises en jour en temps réel concernant vos transactions.

Les Webhooks pour les paiements (anciennement Mises à jour en temps réel) sont essentiels puisqu’ils permettent de vous informer des modifications apportées à des commandes réalisées par le biais de paiements Facebook dans votre application.

Présentation

Les Webhooks fonctionnent sous forme d’abonnement entre Facebook et votre serveur. Votre application s’abonne dans le but de recevoir des mises à jour de Facebook via un point de terminaison HTTPS précis. Quand une commande effectuée dans votre application est mise à jour, nous envoyons une requête POST HTTPS sur ce point de terminaison, informant ainsi votre serveur du changement apporté.

Il existe trois scénarios dans lesquels des mises à jour sont envoyées au serveur utilisé par vos équipes de développement :

Abonnement aux Webhooks

Si vous souhaitez vous abonner aux Webhooks pour les paiements, commencez par créer une URL de point de terminaison public qui reçoit à la fois les requêtes GET HTTPS pour vérifier l’abonnement et les requêtes POST pour modifier les données. La structure de ces deux types de requêtes est décrite ci-dessous. Ensuite, configurez les abonnements vers l’objet payment de votre application. Pour ce faire, deux choix s’offrent à vous :

Quelle que soit la méthode choisie, votre point de terminaison recevra les mêmes données de la même manière. Pour plus d’informations sur les données que votre serveur recevra, consultez la section Votre serveur de rappel.

S’abonner via l’Espace App

Le moyen le plus simple de configurer votre application pour recevoir des mises à jour des Webhooks consiste à utiliser le panneau Paiements de l’Espace App. Il vous suffit de rechercher votre application dans le tableau de bord, puis de cliquer dans l’onglet Payments. La section des Webhooks apparaît alors juste en dessous de la section Paramètres de votre entreprise.

Webhooks pour les paiements

Cet écran présentera alors la liste des statuts d’abonnement de votre application, qu’ils aient été ajoutés par l’intermédiaire de ce panneau ou de l’API. À partir de là, il est possible de modifier l’URL de rappel de l’abonnement et de la tester.

Dans le champ Rappel, vous devez fournir un point de terminaison de serveur publiquement accessible et valide. C’est l’adresse que nous utiliserons pour vérifier l’abonnement, mais aussi pour envoyer les mises à jour. Elle doit pouvoir envoyer des réponses comme indiqué dans la section Votre serveur de rappel.

Enfin, indiquez un token de vérification. Ce token sera envoyé uniquement pendant la phase d’inscription pour vérifier que l’abonnement provient bien d’un lieu sûr. Il ne sera pas envoyé lors des mises à jour régulières des Webhooks.

Tester vos paramètres

Vous devez tester les paramètres de rappel avant d’enregistrer l’abonnement. Cela permettra d’envoyer une requête GET de vérification au point de terminaison contenant les paramètres hub.mode, hub.challenge et hub.verify_token et de vous assurer que vous les gérez correctement. Par exemple, vous devez avoir la garantie que votre point de terminaison renvoie bien hub.challenge à Facebook :

Test de vos paramètres

Dès que vous avez saisi les détails de votre abonnement, n’oubliez pas de cliquer sur le bouton Enregistrer les modifications au bas de la page. Modifier un abonnement n’a rien de compliqué. Il s’agit juste de modifier le contenu des champs, de lancer un nouveau test, puis de réenregistrer le formulaire.

S’abonner via l’API Graph

Il est également possible de configurer les abonnements et d’en établir la liste par programmation, via l’API Graph. Vous aurez besoin du access token de votre application qui est disponible depuis l’Outil Token d’accès ou via le point de terminaison /oauth de l’API Graph.

L’API Subscription est disponible sur le point de terminaison https://graph.facebook.com/[APP_ID]/subscriptions.

Elle vous permet de réaliser trois tâches :

  • Ajouter ou modifier un abonnement (en envoyant une requête POST HTTPS)
  • Dresser la liste de chacun de vos abonnements existants (en envoyant une requête GET HTTPS)

Ajouter et modifier des abonnements

Pour configurer un abonnement, envoyez une requête POST avec les paramètres suivants. Notez que ces paramètres correspondent aux champs du formulaire décrit plus haut :

  • object : comme nous l’avons vu précédemment, ce paramètre correspond au type de l’objet pour lequel vous souhaitez recevoir des mises à jour. Précisez payments.
  • fields : liste séparée par des virgules regroupant les propriétés du type d’objet dont vous souhaitez obtenir une mise à jour. Spécifiez les « actions » et les « litiges ».
  • callback_url : point de terminaison de serveur valide et publiquement accessible.
  • verify_token : chaîne arbitraire, envoyée à votre point de terminaison une fois l’abonnement vérifié.

Quand vous recevez cette requête (par exemple, avec le formulaire tel que configuré ci-dessus), nous lançons une requête GET vers votre URL de rappel pour vérifier qu’elle est bien valide et prête à recevoir des mises à jour. Plus précisément, vous devez avoir la garantie que votre point de terminaison renvoie bien hub.challenge à Facebook.

Attention : étant donné qu’une application ne peut avoir qu’un seul abonnement pour chaque type d’objet, si un abonnement existe pour ce type d’objet, alors les données nouvellement publiées remplaceront les données existantes.

Répertorier vos abonnements

L’émission d’une requête GET HTTPS sur l’API servant aux abonnements renvoie un contenu codé au format JSON qui dresse la liste de vos abonnements. Par exemple :

[
  {
    "object": "payments",
    "callback_url": "https://www.friendsmash.com/rtu.php",
    "fields": ["actions", "disputes"],
    "active": true
  }
]

Vous pouvez utiliser l’Explorateur de l’API Graph pour tester cette API directement sans oublier d’utiliser le token d’accès de votre application.

Votre serveur de rappel

Votre serveur de rappel doit gérer deux types de requêtes. Vérifiez qu’il est possible d’y accéder par l’intermédiaire d’une URL publique pour que les requêtes puissent aboutir.

Vérification de l’abonnement

Tout d’abord, les serveurs Facebook lanceront une requête GET HTTPS unique vers votre URL de rappel au moment où vous essayez d’ajouter ou de modifier un abonnement. Une chaîne de requête sera ajoutée à cette URL de rappel avec les paramètres suivants :

Paramètre Description

hub.mode

La chaîne « subscribe » est transmise dans ce paramètre.

hub.challenge

Une chaîne aléatoire.

hub.verify_token

La valeur verify_token que vous avez spécifiée au moment de créer l’abonnement.

Le point de terminaison doit commencer par vérifier le paramètre hub.verify_token. Cela offre la garantie à votre serveur que la requête a bien été effectuée par Facebook et concerne l’abonnement que vous venez de configurer.

Il s’agit ensuite de simplement renvoyer la valeur hub.challenge qui confirme à Facebook que ce serveur est configuré pour accepter les rappels et empêche les attaques par déni de service (DDoS).

Remarque pour les équipes spécialisées dans le développement en PHP : en PHP, les points et les espaces dans les noms des paramètres de requête sont automatiquement convertis en traits de soulignement. Ainsi, si vous écrivez votre point de terminaison de rappel en PHP, vous devriez accéder à ces paramètres en utilisant $_GET['hub_mode'],$_GET['hub_challenge'] et $_GET['hub_verify_token']. Pour en savoir plus, consultez cette remarque du manuel de langage PHP.

Réception des mises à jour

Après un abonnement réussi, nous émettrons une requête POST HTTPS au point de terminaison de votre serveur à chaque fois qu’une modification aura lieu (cela concernera les connexions ou les champs qui ont été choisis). Vous devez répondre à cette requête avec le code HTTP 200.

Remarque : nous considérons comme une erreur toute réponse HTTP autre que 200. En cas d’erreur, nous tenterons d’envoyer à nouveau la mise à jour des webhooks. Sans réponse correcte de votre part, vous pourriez recevoir la même mise à jour plusieurs fois.

Cette requête aura pour type de contenu application/json tandis que son corps mentionnera une chaîne codée au format JSON et contiendra une ou plusieurs modifications.

Remarque pour les équipes spécialisées dans le développement en PHP : en PHP, pour obtenir les données codées, vous utilisez le code suivant :

$data = file_get_contents("php://input");
$json = json_decode($data);`

Notez que les paramètres hub.mode, hub.challenge et hub.verify_token ne sont pas renvoyés à partir une fois l’abonnement confirmé.

Voici un exemple type de rappel effectué pour un abonnement d’objet payments :

{
  "object": "payments",
  "entry": [
    {
      "id": "296989303750203",
      "time": 1347996346,
      "changed_fields": [
        "actions"
      ]
    }
  ]
}

Il est important de noter que les mises à jour Webhooks vous informent uniquement qu’un paiement en particulier, identifié par le champ id, a été modifié. Une fois la mise à jour reçue, vous devez interroger l’API Graph pour en apprendre davantage sur la transaction et ainsi gérer la modification de manière appropriée.

Remarque : bien qu’il soit possible de regrouper des Webhooks liés à d’autres types d’objets, les mises à jour de paiement ne sont jamais regroupées.

Vous avez ainsi la garantie de recevoir une nouvelle mise à jour à chaque fois qu’une transaction est modifiée, que ce soit par l’utilisateur·ice ou par l’équipe de développement.

Si une mise à jour envoyée à votre serveur échoue, nous vous la renverrons immédiatement, puis plusieurs autres fois, avec une fréquence d’envoi de plus en plus faible, durant les 24 heures suivantes.

Pour chaque requête, nous envoyons un en-tête HTTP X-Hub-Signature-256 qui contient la signature SHA256 de la charge utile. Nous utilisons pour cela la clé secrète à laquelle nous ajoutons le préfixe sha256=. Votre point de terminaison de rappel peut vérifier cette signature pour valider l’intégrité et l’origine de la charge utile.

Réponses aux mises à jour

Après réception d’une mise à jour par votre serveur, nous vous recommandons d’interroger l’API Graph à l’aide du champ id pour en apprendre davantage sur le nouveau statut de la transaction. Libre à vous ensuite d’intervenir selon ce statut.

Les sections suivantes énumèrent tous les modifications d’état susceptibles de déclencher l’envoi d’une mise à jour. Il est globalement possible de les classer dans deux catégories :

  • Les modifications apportées au tableau des actions qui surviennent quand un paiement a lieu de manière asynchrone, quand un remboursement est émis (par vous ou par Facebook) ou dans le cas d’un chargeback.
  • Les modifications apportées au tableau des litiges qui se produisent lorsqu’un·e consommateur·ice ouvre un litige concernant la commande.

Actions

Chaque objet payment contient un tableau intitulé actions qui répertorie l’ensemble des modifications d’état de la transaction. Chaque entrée du tableau actions possède une propriété appelée type qui décrit le type d’action qui a eu lieu. La propriété type peut avoir les valeurs suivantes : charge, refund,chargeback, chargeback_reversal et decline. Pour en obtenir une description complète, cliquez ici.

Voici un exemple de réponse depuis l’API Graph pour un objet de paiement avec les actions associées :

{
   "id": "3603105474213890",
   "user": {
      "name": "Marco Alvarez",
      "id": "500535225"
   },
   "application": {
      "name": "Friend Smash",
      "namespace": "friendsmashsample",
      "id": "241431489326925"
   },
   "actions": [
      {
         "type": "charge",
         "status": "completed",
         "currency": "USD",
         "amount": "0.99",
         "time_created": "2013-03-22T21:18:54+0000",
         "time_updated": "2013-03-22T21:18:55+0000"
      },
      {
         "type": "refund",
         "status": "completed",
         "currency": "USD",
         "amount": "0.99",
         "time_created": "2013-03-23T21:18:54+0000",
         "time_updated": "2013-03-23T21:18:55+0000"
      }
   ],
   "refundable_amount": {
      "currency": "USD",
      "amount": "0.00"
   },
   "items": [
      {
         "type": "IN_APP_PURCHASE",
         "product": "https://www.friendsmash.com/og/friend_smash_bomb.html",
         "quantity": 1
      }
   ],
   "country": "US",
   "created_time": "2013-03-22T21:18:54+0000",
   "payout_foreign_exchange_rate": 1,}`

Dans la mesure où vous avez demandé un abonnement au champ actions au moment de vous inscrire aux Webhooks, nous émettons une mise à jour au moment de la modification du tableau tel que cela vous est décrit plus bas.

Facturation

Initialement, toutes les commandes contiennent une entrée de facturation avec "status": "initiated". Un paiement initié signifie qu’il a simplement été initié et n’est pas encore terminé. Nous n’envoyons aucune mise à jour pour les paiements dont l’état est simplement initié.

Lorsqu’un paiement aboutit, le statut "status": "initiated" se change en "status": "completed" et nous émettons cette fois-ci une mise à jour. Lorsque cette modification s’affiche, vous devez consulter vos relevés de paiement afin de vérifier s’il s’agit d’une transaction nouvelle ou d’une transaction existante et y répondre comme suit :

  • Si vous reconnaissez l’état de cette commande et qu’elle a été traitée par le rappel JavaScript (qu’il est préférable d’utiliser), vous pouvez alors ignorer la mise à jour en toute sécurité ou l’utiliser comme confirmation supplémentaire.
  • Si vous reconnaissez cette commande, mais que son état est initiated, vous pouvez la traiter et émettre l’article virtuel associé ou la devise à l’attention du consommateur ou de la consommatrice. Ce paiement peut alors être indiqué comme terminé.
  • Si vous ne reconnaissez pas l’état de la commande, cela indique que le flux côté client·e ne s’est pas terminé correctement. Cela est probablement dû à un problème de connexion ou de fermeture du navigateur par le consommateur ou la consommatrice au milieu de la procédure. Vous pouvez toujours traiter et terminer cette commande en toute sécurité, car Facebook reste une source fiable en matière de facturation.

Vous recevrez également des mises à jour de paiement avec pour état "status": "failed". Aucun traitement n’est possible ici.

Remboursement

À chaque fois que vous émettez un remboursement via l’API Graph, vous recevez une mise à jour. Comme avec "type": "charge", un remboursement peut également se voir attribuer un statut variable auquel il vous faudra prêter attention. Il est notamment possible qu’un remboursement échoue, le plus souvent en raison d’une erreur de traitement ou de connexion. Dans ce cas, il vous faudra tenter d’émettre à nouveau le remboursement.

Chargebacks, annulations de chargeback et refus

Comme pour les remboursements, une notification est également envoyée lorsqu’un chargeback, une annulation de chargeback ou un refus a été émis. Un objet de chargeback, d’annulation de chargeback ou de refus est alors ajouté au tableau des actions des données renvoyées par l’API Graph concernant le paiement.

Litiges

Nous vous préviendrons en cas de litige en émettant une mise à jour. Dans ce cas, un nouveau tableau "disputes" apparaîtra pour l’objet payment. Ce tableau mentionnera l’heure du litige, la raison pour laquelle le consommateur ou la consommatrice l’a ouvert et son adresse e-mail que vous pourrez utiliser pour le ou la contacter directement en vue de trouver une solution.

Voici un exemple de réponse depuis l’API Graph pour une transaction assortie d’un litige :

{
   "id": "990361254213890",
   "user": {
      "name": "Marco Alvarez",
      "id": "500535225"
   },
   "application": {
      "name": "Friend Smash",
      "namespace": "friendsmashsample",
      "id": "241431489326925"
   },
   "actions": [
      {
         "type": "charge",
         "status": "completed",
         "currency": "USD",
         "amount": "0.99",
         "time_created": "2013-03-22T21:18:54+0000",
         "time_updated": "2013-03-22T21:18:55+0000"
      }
   ],
   "refundable_amount": {
      "currency": "USD",
      "amount": "0.99"
   },
   "items": [
      {
         "type": "IN_APP_PURCHASE",
         "product": "https://www.friendsmash.com/og/friend_smash_bomb.html",
         "quantity": 1
      }
   ],
   "country": "US",
   "created_time": "2013-03-22T21:18:54+0000",
   "payout_foreign_exchange_rate": 1,
   "disputes": [
      {
         "user_comment": "I didn't receive my item! I want a refund, please!",
         "time_created": "2013-03-24T18:21:02+0000",
         "user_email": "email\u0040domain.com",
         "status": "resolved", 
         "reason": "refunded_in_cash"
      }
   ]
}

Pour en savoir plus sur la façon de répondre aux litiges et d’émettre des remboursements, veuillez consulter la section Paiements : Gestion des litiges et des remboursements.