Automatiser son backoffice avec Paypal IPN

Paypal possède une grande notoriété et je ne vous le présenterai donc pas. C’est un bon choix d’intermédiaire pour récolter des paiements sur son site internet. Qu’il soit seul ou couplé à une solution bancaire, Paypal est devenu indispensable. Seulement, Paypal propose une multiplicité de moyens d’intégration sur son site. Du bouton HTML à l’API NVP, il est parfois difficile d’automatiser son backoffice. De l’envoi d’un email de confirmation de commande à la synchronisation de sa base de données clients, l’automatisation est plus pratique – et efficace – que d’attendre les mails de confirmation paiement de Paypal et d’agir manuellement.

Différentes technologies de paiement

Dans l’ensemble, Paypal dispose de trois moyens d’intégrer sa solution de paiement :

  • Une API SOAP orientée objet, implémentable dans divers langages, qui repose sur des requêtes et réponses entre votre site et les serveurs de Paypal,
  • Une API NVP, facilement utilisable en procédural, où les échanges entre votre site et Paypal se font via l’encodage de données dans les url,
  • Enfin, la création de simples boutons html contenant vos informations de paiement (objet, prix…), qui envoie l’internaute vers la page Paypal de paiement.

IPN : Instant Payment Notification

schéma paypal ipn
Illustration du fonctionnement de l’IPN

L’IPN, s’est en fait le serveur de Paypal qui va se connecter à votre site pour vous avertir d’un paiement, d’un échec… C’est donc un moyen pour vous de savoir si vous avez été payé pour telle ou telle chose, quand et combien, et d’agir en conséquence. À chaque fois que Paypal veut vous notifier d’un paiement (ou annulation etc), il se connecte à votre site via une url que vous aurez définie et transmet donc les informations à votre script.

Cependant, les deux API de Paypal, de la même manière que l’API ATOS, fonctionnent selon le modèle de dialogue client-serveur, et de ce fait, votre site est immédiatement au courant de la réussite ou de l’échec du paiement. Vous vous dîtes alors, à juste titre, que l’intérêt de l’IPN est limité, il servira uniquement aux sites se servant des boutons html et qui n’ont donc pas immédiatement connaissance du résultat du paiement. Pas tout à fait…

D’une part, c’est sans compter par exemple, sur la possibilité des paiements récurrents de Paypal. Dans ce cas, votre utilisateur souscrit un abonnement, donc au premier paiement, il passe par votre site et l’API (ou les boutons html), mais ensuite, il est débité à l’initiative de Paypal sans devoir repasser par votre site, et donc votre API ne vous sera d’aucun secours pour être notifié de la réussite ou de l’échec du paiement. D’autre part, un paiement peut-être annulé, ou remboursé, et cela s’effectue aussi en dehors de votre API SOAP ou NVP. En revanche, nous l’avons évoqué plus haut, la connexion de l’IPN est à l’initiative de Paypal, ce dernier notifiera donc votre site aussi pour la réception d’un paiement récurrent. C’est dans ce cas que l’IPN prend tout son intérêt.

La mise en place

La mise en place de l’IPN peut se faire dans divers langages, ASP, Perl, JAVA, ColdFusion… Vous retrouverez des exemple de codes sur le site des développeurs. Pour notre part, nous allons mettre en place l’IPN en PHP. Je vous laisse donc directement avec le code, dûment commenté :

<?php
    
// prépare la requête de vérification
$req = "cmd=_notify-validate";

// ajoute le message IPN au format NVP à la requête de vérification
foreach ($_POST as $key => $value) {
  $value = urlencode(stripslashes($value));
  $req .= '&$key=$value';
}


// définition des headers pour la requête de vérification
$header  = "POST /cgi-bin/webscr HTTP/1.0rn";

// test 
//$header .= "Host: www.sandbox.paypal.com:443rn";

// production
$header .= "Host: ipnpb.paypal.com:443rn";      

$header .= "Content-Type: application/x-www-form-urlencodedrn";
$header .= "Content-Length: " . strlen($req) . "\r\n\r\n";


// Ouverture du socket

// test
//$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);

// production
$fp = fsockopen ('ssl://ipnpb.paypal.com', 443, $errno, $errstr, 30);

// s'il y a une erreur lors de l'ouverture du socket
if (!$fp) {
  // on s'envoie un mail pour être informé de l'erreur
  $msg = 'Erreur de socket, l\'url n\'a pas pu être ouverte';
  mail('payments@monmail.fr', 'erreur socket', $msg);
}

else {
  // on post la requête de vérification
  fputs ($fp, $header . $req);

  // créé une boucle tant qu'on est pas arrivé à la fin du fichier
  while (!feof($fp)) {
    // lit la réponse de paypal
    $res = fgets ($fp, 1024);
        
    // si paypal répond VERIFIED, 
    // tout s'est bien déroulé et on peut procéder à nos traitements
    if (strcmp ($res, 'VERIFIED') == 0) {
      // type de transaction
      // $_POST['txn_type'] 
            
      // mail du compte paypal à qui est destiné le paiement
      // $_POST['receiver_email']
            
      // montant
      // $_POST['mc_gross']
            
      // id de la transaction
      // $_POST['txn_id']
            
      // champ personnalisé
      // $_POST['custom']
    }

    // si la transaction est invalide
    else if (strcmp ($res, 'INVALID') == 0) {
      // on s'envoie un mail pour être informé de l'erreur
      $msg = 'Message de l\'IPN : '.$res;
      mail('payments@monmail.fr', 'erreur IPN', $msg);
    }
  }  
    
  fclose ($fp);
}

Il y a beaucoup beaucoup de variables disponibles. Il est toujours utile de faire un foreach de $_POST et de logger le résultat ou de se l’envoyer par mail pour voir ce qu’il contient. Il va aussi vous falloir jouer un peu avec le simulateur de messages IPN. Cependant, le simulateur n’est pas parfaitement complet, en effet, il n’offre pas toutes les possibilités, par exemple les paiements récurrents n’y figurent pas… Il faudra donc finir par se faire quelques tests « réels » en s’envoyant de vrais paiements puis en se remboursant entre deux vrais comptes Paypal. Enfin, face à la richesse des variables et des infos, il vous sera bien utile de jeter un œil à la doc qui regroupe les différentes variables IPN.

Par ailleurs, je souligne l’intérêt de la variable custom, qui permet par exemple, de faire passer l’id d’un membre et d’ainsi créditer son compte du paiement. Celle-ci se transmet très facilement, par exemple via les boutons html. Notons néanmoins qu’elle ne permet du coup pas le chiffrement du boutons :

<input type="hidden" name="custom" value="2">

À propos du chiffrement, sachez que Paypal permet de chiffrer les boutons HTML; Ils ne sont ainsi pas modifiable dans le code de la page. Je préfère pour ma part les boutons non chiffrés (avec une validation à posteriori des montants etc.) car on peut directement les modifier côté serveur ou même directement en javascript. J’ai remarqué que par défaut Paypal enregistre les boutons si vous êtes connecté. Déconnectez-vous avant tout puis rendez-vous sur la page de création de bouton.

Enfin, une fois votre script en place, vous devez configurer votre serveur web pour qu’il soit accessible via une url particulière. Ensuite il faut vous connecter à votre compte paypal et aller à Mes préférences > mes ventes > notifications instantanées de paiement, pour configurer l’url auquel paypal doit notifier votre site.

interface de configuration de l'ipn paypal
Page de configuration de l’IPN

Je vous souhaite bien entendu une bonne mise en place, et par la suite, de recevoir beaucoup de paiements !

Déjà 13 réponses, rejoignez la discussion !

  • Franck

    dit :

    Pourquoi la quasi totalité des tutos, outre le fait d’user d’un même scripte, font l’impasse systématique sur l’intégration des variable ipn dans la base de donnée du serveur client ?
    Est-ce à dire que c’est impossible ???

    Merci

    Franck

    • Buzut

      dit :

      Si je comprend bien ta demande, tu cherches à enregistrer en BDD les données que tu reçois de l’ipn, telles que le montant, la date, la ref transaction etc.

      Si oui, la plupart des tuto n’en parlent certainement pas puisqu’une fois tes variables récupérées, les enregistrer dans la base n’est pas spécifique à IPN mais à la base que tu utilises et à l’interface choisie pour te connecter à cette dernière (ex. PDO).

      • Franck

        dit :

        Si je crais un tuto pour enseigner la conduite auto, même si la motorisation est multiple, je ne ferais pas l’impasse sur le fait qu’une bonne conduite ne se fait pas sans énergie (essence, gasoil, gaz, électricité…
        Donc en ce qui concerne l’ipn il me semble NORMAL d’évoquer l’enregistrement en BDD, ne serait-ce que pour la manière de récupérer les infos (commun à TOUS les traitements possible) et ensuite trois mots pour expliquer que l’enregoistrement dépend du mode de « stockage » !
        Ou je n’ai rien compris, ou le but d’un tuto est d’apporter une aide su un sujet non maitrisé par l’utilisateur dudit tuto !!

        • Buzut

          dit :

          Les infos sont dans des variables, je les donne et dit ce qu’elles contiennent : $_POST[‘txn_type’] … c’est donc la base pour récupérer les infos, les enregistrer en base, ce n’est pas du ressort de ce tuto.

          Oui un tuto est sensé apporter une aide sur un sujet nom maitrisé, en l’occurrence paypal ipn. Pas MySQL, ou postgre ou php. Il faudrait que j’explique comment on se sert de php aussi ? Et d’un ordinateur, puisque pour se servir de paypal, le prérequis est aussi de savoir se servir d’un ordinateur.

          L’enregistrement en base de données, je le répète, dépend du moteur de base, du schéma qui est propre à l’utilisateur et de pleins d’autres facteurs. Cela dépend donc de l’utilisateur et j’estime que les gens qui lisent ce tuto savent se servir d’une base de données. Si ce n’est pas le cas, il y a sur le net de très bon tutos sur la multitude de bases existantes.

          • Franck

            dit :

            Ce qui se conçoit bien s’énonce clairement et les mots pour le dire arrivent aisément : donc sur ce sujet pécis il n’est pas question de donner un cours hors sujet, mais SIMPLEMENT d’indiquer comment retrouver les variables et à quelle étape les traiter, à moins qu’il faille un tuto pour expliquer qu’à un moment la procédure expliquée devient hors sujet?
            D’où :
            Si je crais un tuto pour enseigner la conduite auto, même si la motorisation est multiple, je ne ferais pas l’impasse sur le fait qu’une bonne conduite ne se fait pas sans énergie (essence, gasoil, gaz, électricité…)
            Sans avoir à donner des cours de chimie et de physique quant à la composition ou à la production de l’énergie choisie !!!

  • Vincent

    dit :

    Bonjour,

    et merci pour ce tuto qui tombe à point: j’essaie de mettre en place un principe d’abonnement sur mon site web et j’avoue que tout n’est pas simple, notamment la mise à jour de ma BDD en fonction des règlements mensuels de mes clients.

    Mais dans votre article, je ne comprends pas plusieurs choses…
    D’un côté vous dites « […]la connexion de l’IPN est à l’initiative de Paypal, ce dernier notifiera donc votre site aussi pour la réception d’un paiement récurrent. C’est dans ce cas que l’IPN prend tout son intérêt. »
    De l’autre votre code est à l’initiative du site web (et doit fonctionner par cron j’imagine).
    Quelle est la bonne solution? Doit-on attendre que l’IPN contacte le site web pour enregistrer un paiement récurrent ?
    Tout ceci est assez confus pour le moment de mon côté.

    Merci pour votre aide.
    Vincent

    • Buzut

      dit :

      Bonjour Vincent,

      On comprend son fonctionnement à travers le schéma et cette phrase juste ensuite : « L’IPN, c’est en fait le serveur de Paypal qui va se connecter à votre site pour vous avertir d’un paiement, d’un échec… ». Cependant, j’ai ajouté en bas fin d’article la procédure pour enregistrer l’url de notif dans paypal, ce sera plus clair ainsi.

      En réalité le code ipn réside donc sur votre site web mais il n’est pas activé par un cron. Il répond à une certaine URL que vous spécifiez dans l’interface de paypal. A chaque fois que paypal veut vous notifier d’un paiement (ou annulation etc), il se connecte à votre site via cette url et transmet donc les informations à votre script.

      Ai-je éclairé vos lanternes ?

      • Vincent

        dit :

        Bonsoir Franck,

        ok bien compris. J’aurais pu le déceler puisqu’en effet vous parcourez les valeurs du $_POST en début de script… mea culpa !
        Merci pour votre réponse et pour ce tuto, c’est effectivement limpide maintenant. Je vous tiens au courant dès que ça fonctionne.

        Bonne soirée,
        Vincent

        • Franck

          dit :

          En fait le défaut de beaucoup de tuto est de tenir pour acquis des connaissances dont l’absence est la raison d’être du tuto…
          Mon expérience personnelle : en 3 ans j’ai appris beaucoup de langages pour le développement internet, mais je ne veux pas passer ma vie à apprendre encore et encore simplement pour l’intégration d’un script…
          Pourtant il semble que beaucoup de forum ne sont là que pour se poser en « enseignant » pour ne donner que la voie…
          Rassurez-vous, hormis le point de détail relevé, votre tuto rempli son rôle…

          Cordialement

  • Mark

    dit :

    Bonjour à tous, merci pour ce bon tuto. Cependant j’aimerais savoir comment faire si le client fait un paiement différé par virement. En appliquant ce tuto, le paiement est « VERIFIED » et son abonnement est validé. Sauf que le client peut annulé son virement par la suite.
    Merci

    • Buzut

      dit :

      Côté sécurisation des paiements et remboursement, c’est du côté du compte qu’il faut voir. Est-il possible de le bloquer ? À voir avec Paypal mais tu ne pourras pas agir là dessus dans le code…

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *