Passerelle de Paiement Paddle

Acceptez les paiements via Paddle : une plateforme « merchant of record » qui gère les paiements, les taxes et la conformité. S’intègre au Shop Larapen via le contrat PaymentGatewayInterface.

Overlay de Paiement Paddle

Les clients paient via l’overlay de paiement intégré de Paddle, propulsé par Paddle.js v2. Aucune redirection hors de votre site.

Merchant of Record

Paddle gère la taxe de vente, la TVA et la conformité dans le monde entier. Vous recevez des versements nets.

Piloté par Webhooks

Les mises à jour de statut des commandes sont confirmées via des webhooks signés pour un traitement fiable des paiements.

Support des Remboursements

Traitez des remboursements complets ou partiels directement depuis le panneau d’administration via l’API Paddle Adjustments.

Cas d’Utilisation

Vente de Produits Numériques

Vous vendez des produits numériques (thèmes, plugins, e-books) via le Shop Larapen et souhaitez que Paddle gère la conformité fiscale mondiale et les versements.

  • Installez l’add-on Paddle en même temps que l’add-on Shop.
  • Configurez vos identifiants API Paddle dans le panneau d’administration.
  • Les clients sélectionnent Paddle au moment du paiement et paient via l’overlay.
  • Paddle collecte les taxes, traite le paiement et vous envoie le revenu net.

Boutique de Produits Physiques ou Mixtes

Vous vendez des produits physiques ou un mélange de produits physiques et numériques et souhaitez une passerelle de paiement fiable.

  • Paddle prend en charge les cartes de crédit/débit, PayPal, Apple Pay, Google Pay et les méthodes de paiement locales.
  • Les commandes sont confirmées via des webhooks, garantissant qu’aucun paiement n’est perdu même si le client ferme son navigateur.

Tests en Sandbox

Utilisez l’environnement sandbox de Paddle pour le développement et les tests avant de passer en production.

  • Définissez l’environnement sur « Sandbox » dans les paramètres d’administration.
  • Utilisez les numéros de carte de test de Paddle pour simuler des paiements.
  • Passez en « Production » lorsque vous êtes prêt pour les paiements réels.

Prérequis

  • Larapen CMS v1.0.0 ou ultérieur
  • PHP 8.3+
  • MySQL 8.0+
  • L’add-on Shop doit être installé et actif (dépendance déclarée)
  • Un compte Paddle : paddle.com
  • Paddle PHP SDK (paddle/paddle-php-sdk) installé via Composer
Note : L’add-on dépend de l’add-on Shop. Il ne peut pas être activé sans que l’add-on Shop soit installé et actif au préalable.

Installation

Étape 1 : Placer l’Add-on

Copiez ou créez un lien symbolique du dossier paddle dans le répertoire « extensions/addons » de votre Larapen :

Étape 2 : Installer le SDK PHP Paddle

Étape 3 : Activer l’Add-on

Allez dans Admin → Add-ons → Add-ons Installés et activez Passerelle de Paiement Paddle.

Étape 4 : Exécuter les Migrations

Cela crée 2 tables : paddle_customers et paddle_transactions.

Étape 5 : Définir les Permissions

L’add-on enregistre 2 permissions (voir Permissions). Attribuez-les aux rôles d’administration via Admin → Utilisateurs → Rôles & Permissions.

Étape 6 : Configurer

Naviguez vers Admin → Paddle → Paramètres et entrez votre clé API, votre jeton côté client, votre ID vendeur et votre secret webhook. Voir Configuration et Obtenir les Identifiants Paddle.

Étape 7 : Configurer les Webhooks dans Paddle

  1. Allez dans votre Tableau de Bord Paddle → Outils Développeur → Notifications.
  2. Créez une nouvelle destination de notification.
  3. Définissez l’URL sur https://votresite.com/paddle/webhook.
  4. Sélectionnez ces événements : transaction.completed, transaction.payment_failed, transaction.updated, adjustment.created, adjustment.updated.
  5. Copiez le secret webhook et collez-le dans les paramètres d’administration.

Configuration

Tous les paramètres sont gérés dans Admin → Paddle → Paramètres (stockés dans la table settings, groupe paddle).

Paramètre Description Par défaut
paddle_api_key Clé API Paddle pour les appels API côté serveur (transactions, remboursements). Chiffrée au repos. (vide)
paddle_client_token Jeton côté client Paddle pour initialiser Paddle.js sur le frontend. Chiffré au repos. Les jetons sandbox commencent par test_, les jetons live par live_. (vide)
paddle_webhook_secret Clé secrète pour vérifier les signatures des webhooks Paddle (HMAC-SHA256). Chiffrée au repos. (vide)
paddle_environment Environnement Paddle : sandbox pour les tests, production pour les paiements réels. sandbox
paddle_seller_id Votre ID vendeur/seller Paddle. Requis pour l’initialisation de Paddle.js. (vide)
paddle_currency Code devise (par ex., USD, EUR, GBP). Doit correspondre à la devise de votre boutique. USD
Sécurité : La clé API, le jeton client et le secret webhook sont chiffrés avec Crypt::encryptString() de Laravel avant d’être stockés dans la base de données. Ils sont déchiffrés au moment de l’exécution lorsque le PaddleServiceProvider démarre.

Variables d’Environnement

Les variables d’environnement servent de valeurs par défaut. Les paramètres enregistrés dans le panneau d’administration les remplacent.

Note : Les variables d’environnement sont utilisées comme valeurs par défaut de secours. Les paramètres enregistrés dans le panneau d’administration ont la priorité et les remplacent.

Obtenir les Identifiants Paddle

Clé API & Jeton Côté Client

  1. Connectez-vous à votre Tableau de Bord Paddle (ou au Tableau de Bord Sandbox pour les tests).
  2. Naviguez vers Outils Développeur → Authentification.
  3. Copiez votre Clé API (utilisée pour les appels API côté serveur).
  4. Copiez votre Jeton Côté Client (utilisé pour l’initialisation de Paddle.js).

ID Vendeur

  1. Dans le Tableau de Bord Paddle, votre ID Vendeur est affiché dans les paramètres du compte ou l’URL.
  2. Copiez l’ID numérique et entrez-le dans les paramètres d’administration.

Secret Webhook

  1. Allez dans Outils Développeur → Notifications dans le Tableau de Bord Paddle.
  2. Créez une nouvelle destination de notification avec l’URL https://votresite.com/paddle/webhook.
  3. Sélectionnez les événements auxquels vous abonner (voir Événements Supportés).
  4. Copiez le secret webhook généré et entrez-le dans les paramètres d’administration.
Important : Les environnements sandbox et production utilisent des identifiants différents. Les jetons client sandbox commencent par test_ et les jetons live par live_. Assurez-vous que vos identifiants correspondent à l’environnement sélectionné.

Admin : Paramètres

La page des paramètres (Admin → Paddle → Paramètres) est organisée en deux sections.

Identifiants API

Trois champs de mot de passe masqués avec des boutons afficher/masquer :

  • Clé API : Votre clé API Paddle depuis Outils Développeur > Authentification. Utilisée pour tous les appels API côté serveur (création de transactions, traitement des remboursements).
  • Jeton Côté Client : Votre jeton côté client Paddle. Utilisé pour initialiser Paddle.js sur la page de paiement. Les jetons sandbox commencent par test_.
  • Secret Webhook : Utilisé pour vérifier la signature HMAC-SHA256 des requêtes webhook entrantes.
Note : Laissez les champs d’identifiants vides pour conserver les valeurs actuellement stockées. Tous les identifiants sont chiffrés avant d’être stockés dans la base de données. Ne partagez jamais votre clé API.

La page affiche également un panneau d’information avec des liens directs vers :

  • Tableau de Bord Paddle (production et sandbox)
  • Outils Développeur > Authentification (clés API)
  • Outils Développeur > Notifications (webhooks)
  • Documentation de l’API Paddle
  • Numéros de carte de test pour les tests sandbox

Options de Paiement

  • Environnement : Menu déroulant pour sélectionner sandbox (test) ou production (réel).
  • ID Vendeur : Champ texte pour votre ID vendeur/seller Paddle. Requis pour l’initialisation de Paddle.js.
  • Devise : Code devise à 3 caractères (par ex., USD, EUR, GBP). Doit correspondre à la devise de votre boutique.

Flux de Paiement

L’add-on Paddle utilise un flux de paiement par overlay propulsé par Paddle.js v2. Voici le cycle de vie complet du paiement :

  1. Le client sélectionne Paddle : Sur la page de paiement de la boutique, le client sélectionne « Paddle » comme méthode de paiement. Un message d’information apparaît : « Vous serez redirigé vers le paiement sécurisé de Paddle. »
  2. Soumission du formulaire (AJAX) : Lorsque le client soumet le formulaire de paiement, JavaScript intercepte la soumission et l’envoie via fetch() avec des en-têtes JSON.
  3. Le serveur crée une transaction Paddle : La méthode PaddleGateway::createPaymentIntent() :
    • Crée une transaction hors catalogue via l’API Paddle avec le montant, la devise et les métadonnées de la commande.
    • Stocke un enregistrement local paddle_transactions liant l’ID de transaction Paddle à la commande.
    • Lie le client Paddle à l’utilisateur local (si authentifié).
    • Renvoie l’ID de transaction Paddle au frontend.
  4. L’overlay Paddle.js s’ouvre : Le JavaScript ouvre l’overlay de paiement Paddle en utilisant Paddle.Checkout.open() avec l’ID de transaction.
  5. Le client complète le paiement : Le client entre ses informations de paiement dans l’overlay Paddle.
  6. Callback de paiement terminé : Sur checkout.completed, le JavaScript redirige vers l’URL de retour (/paddle/return?_ptxn={transaction_id}).
  7. Confirmation par URL de retour : La méthode PaddleController::return() appelle confirmPayment() pour vérifier le statut de la transaction via l’API Paddle. Si terminée, la commande est marquée comme payée et le client est redirigé vers la page de succès.
  8. Confirmation par webhook : Paddle envoie également un webhook transaction.completed comme sauvegarde fiable. Cela garantit que les commandes sont marquées comme payées même si le client ferme son navigateur avant la redirection de retour.

Gestion des Webhooks

Les webhooks sont reçus à POST /paddle/webhook. Ce point d’entrée est exclu de la protection CSRF et du middleware web.

Événements Supportés

Événement Action
transaction.completed Marque la transaction locale comme terminée, appelle markAsPaid() sur le payable (commande), et crée un enregistrement shop_transactions avec les détails du paiement.
transaction.payment_failed Marque la transaction locale comme échouée, appelle markPaymentFailed() sur le payable, et crée un enregistrement de transaction échouée avec le code d’erreur.
adjustment.created Si l’action de l’ajustement est refund et le statut est approved ou completed, met à jour le statut de paiement de la commande en refunded.
adjustment.updated Même traitement que adjustment.created : vérifie les changements de statut de remboursement.
transaction.updated Configuré dans la liste des événements webhook mais actuellement traité par le cas par défaut (ignoré).

Vérification de Signature

Tous les webhooks entrants sont vérifiés à l’aide de signatures HMAC-SHA256. Paddle envoie la signature dans l’en-tête HTTP Paddle-Signature au format :

Le processus de vérification :

  1. Analyser les valeurs ts (horodatage) et h1 (hash) depuis l’en-tête.
  2. Calculer HMAC-SHA256(timestamp + ':' + rawBody, webhookSecret).
  3. Comparer le hash calculé avec la valeur h1 reçue en utilisant hash_equals().
  4. Si la signature est invalide ou le secret webhook est vide, renvoyer une réponse 400.
Important : Le secret webhook doit être configuré pour que la vérification de signature fonctionne. Sans lui, toutes les requêtes webhook seront rejetées avec une erreur « Invalid signature ».

Remboursements

L’add-on prend en charge les remboursements complets et partiels via l’API Paddle Adjustments.

Comment Fonctionnent les Remboursements

  1. Un administrateur initie un remboursement depuis la page de gestion des commandes de la boutique.
  2. La méthode PaddleGateway::refund() :
    • Récupère la transaction Paddle pour obtenir les IDs des articles.
    • Crée un ajustement partiel avec Action::Refund() sur le premier article.
    • Crée un enregistrement shop_transactions de type refund.
  3. Paddle traite le remboursement et envoie un webhook adjustment.created.
  4. Le gestionnaire de webhook met à jour le statut de la commande en refunded si l’ajustement est approuvé.

Statuts de Remboursement

Statut Description
approved Remboursement approuvé et traité immédiatement. Commande marquée comme remboursée.
pending Remboursement soumis mais en attente d’approbation Paddle. Le statut de la commande est mis à jour lorsque le webhook adjustment.updated arrive.
rejected Remboursement rejeté par Paddle. Aucun changement de statut de commande.

Mise à Jour

Étape 1 : Remplacer les Fichiers

Remplacez le répertoire de l’add-on par la nouvelle version.

Étape 2 : Mettre à Jour les Dépendances Composer

Étape 3 : Exécuter les Migrations

Étape 4 : Vider les Caches

Étape 5 : Vérifier

Visitez Admin → Paddle → Paramètres et confirmez que vos identifiants sont toujours configurés. Effectuez un paiement de test en mode sandbox pour vérifier l’intégration.

Sauvegarde d’abord : Sauvegardez toujours votre base de données avant d’exécuter des migrations sur un système de production.

Dépannage

L’overlay de paiement Paddle ne s’ouvre pas

  • Assurez-vous que le paddle_client_token est configuré dans les paramètres d’administration.
  • Vérifiez la console du navigateur pour les erreurs JavaScript. Un jeton client manquant ou invalide affichera Paddle client token not configured.
  • Vérifiez que le jeton correspond à l’environnement : les jetons sandbox commencent par test_, les jetons de production par live_.
  • Assurez-vous que Paddle.js se charge : vérifiez que https://cdn.paddle.com/paddle/v2/paddle.js n’est pas bloqué par votre Content Security Policy ou votre bloqueur de publicités.

Le paiement ne se confirme pas : la commande reste en « pending »

  • Vérifiez que votre URL webhook (/paddle/webhook) est accessible depuis Internet. Paddle doit pouvoir envoyer des requêtes POST.
  • Vérifiez que le paddle_webhook_secret est défini et correspond au secret dans votre Tableau de Bord Paddle.
  • Consultez storage/logs/laravel.log pour les erreurs liées aux webhooks.
  • Dans le Tableau de Bord Paddle sous Notifications, vérifiez si les livraisons de webhooks échouent.

Le webhook renvoie 400 : « Invalid signature »

  • Le paddle_webhook_secret dans les paramètres d’administration ne correspond pas au secret du Tableau de Bord Paddle.
  • Si vous avez récemment renouvelé le secret webhook, mettez-le à jour dans les paramètres d’administration.
  • Assurez-vous que le corps brut de la requête n’est pas modifié par un middleware avant la vérification de signature.

La création de transaction échoue : « Paddle transaction creation failed »

  • Vérifiez que la paddle_api_key est correcte et n’a pas été révoquée.
  • Assurez-vous que le paddle_seller_id est défini.
  • Vérifiez que le code devise est valide et supporté par Paddle.
  • Consultez les logs du serveur pour le message d’erreur complet de l’API Paddle.
  • Si vous utilisez le sandbox, assurez-vous que la clé API est une clé sandbox (pas de production).

Le remboursement échoue : « Paddle refund failed »

  • Vérifiez que la transaction originale était terminée (seules les transactions terminées peuvent être remboursées).
  • Vérifiez que le montant du remboursement ne dépasse pas le montant de la transaction originale.
  • Certains ajustements Paddle nécessitent une approbation manuelle : consultez le Tableau de Bord Paddle.
  • Consultez les logs du serveur pour l’erreur détaillée de l’API Paddle.

La passerelle n’apparaît pas sur la page de paiement

  • Assurez-vous que l’add-on Paddle est activé dans Admin → Add-ons.
  • Assurez-vous que paddle_api_key et paddle_seller_id sont configurés (isAvailable() vérifie les deux).
  • Vérifiez que l’add-on Shop est actif (Paddle en dépend).

Le client n’est pas lié à un ID client Paddle

  • La liaison du client se fait automatiquement lors de la création de la transaction lorsque le payable a un ID utilisateur.
  • Les paiements en tant qu’invité (sans utilisateur authentifié) ne créent pas d’enregistrement paddle_customers.
  • Consultez les logs du serveur pour les avertissements de linkCustomer().

Les paramètres ne s’enregistrent pas : les identifiants apparaissent vides après la sauvegarde

  • Les identifiants sont chiffrés avant le stockage et déchiffrés pour l’affichage. Si la APP_KEY a changé, les valeurs précédemment chiffrées ne peuvent pas être déchiffrées.
  • Saisissez à nouveau tous les identifiants après un changement de APP_KEY.
  • Vérifiez que la table settings est accessible en écriture.

Cet article vous a-t-il été utile ?

Merci pour votre retour !

Besoin d'aide ? Créez un ticket de support

Créer un Ticket