Un système de gestion de clés de licence basé sur les marketplaces pour Larapen, avec vérification API, suivi des activations par domaine/machine, blocage des abus et intégration de webhooks.

Marketplaces multiples

Clés vendues sur la Boutique du site, sur Envato Market et sur Gumroad, clés émises à la main et clés transmises par des webhooks externes : tout dans un seul système.

Suivi des activations

Suivez les activations par domaine, identifiant machine ou IP. Appliquez des limites par clé (ex. 3 domaines max).

Espace client

Les clients enregistrent un code d’achat, consultent les licences qu’ils possèdent et libèrent un domaine qu’ils n’utilisent plus : sur votre propre site.

API REST

Points de terminaison de vérification, activation et désactivation pour l’intégration client.

Liste de blocage Nouveau

Bannissez par IP, par domaine ou par clé, avec des règles .htaccess optionnelles qui bloquent les abus au niveau d’Apache, avant même que PHP ne soit chargé. Bannissement automatique en cas de dépassement de la limite de débit.

Journaux API & cache Nouveau

Piste d’audit complète de chaque appel API, avec les données sensibles masquées. Une couche de cache centralisée évite toute requête en base lors des vérifications servies par le cache.

Cas d’utilisation

Application SaaS

Votre produit SaaS utilise des clés de licence auto-hébergées pour contrôler les niveaux d’abonnement.

  • Chaque plan correspond à un Produit, et le niveau du plan est porté par le type de licence de la clé : standard (Starter), extended (Pro).
  • L’application appelle GET /api/licenses/verify au démarrage et lit product et license_type pour débloquer le bon niveau.
  • Pas besoin d’activation par domaine : juste la vérification.

Application de bureau

Une application de bureau est licenciée par machine.

  • Au lancement, l’application appelle POST /api/licenses/activate avec un machine_id.
  • L’application appelle périodiquement GET /api/licenses/verify pour vérifier la validité.
  • Lorsque l’utilisateur décommissionne une machine, il appelle POST /api/licenses/deactivate pour libérer l’emplacement.

Plugin / Thème WordPress

Un plugin WordPress premium valide sa licence sur le site du client.

  • L’administrateur entre la clé dans les paramètres WP. Le plugin appelle POST /api/licenses/activate avec domain = site_url().
  • La vérification s’exécute quotidiennement via WP-Cron en utilisant GET /api/licenses/verify.
  • Si la limite d’activation est atteinte, le client doit désactiver un ancien domaine avant d’en activer un nouveau.

Niveaux d’accès API

Vous vendez un accès API avec différentes limites de débit par plan.

  • Un Produit par plan, Basic et Enterprise, ou un seul Produit dont les clés portent un type de licence standard ou extended.
  • Votre passerelle API appelle GET /api/licenses/verify, lit product et license_type, et les associe à la limite de débit qu’elle applique.

Produits Envato (CodeCanyon)

Vous vendez un produit sur CodeCanyon et souhaitez une vérification automatique des licences.

  • Activez la marketplace Envato et renseignez votre jeton API et votre nom d’utilisateur auteur.
  • Les clients entrent leur code d’achat Envato. Le système le vérifie directement auprès de l’API Envato.
  • Pas besoin de création manuelle de clé : la marketplace Envato crée la clé lors de sa première vérification.

Bibliothèque / Plugin JavaScript

Vous vendez un composant d’éditeur JS premium. Chaque client reçoit une clé de licence valide pour N domaines.

  • Au chargement de la page, la bibliothèque appelle POST /api/licenses/activate avec la clé et le domaine actuel.
  • Le serveur vérifie la clé, l’active sur le domaine (comptabilisé dans la limite) et retourne le type de licence, le produit et l’expiration via GET /api/licenses/verify : la bibliothèque active ainsi le niveau que le client a payé (standard, extended, …).

Prérequis

  • Larapen CMS v1.0.0 ou ultérieur
  • PHP 8.3+
  • MySQL 8.0+
  • Une installation Larapen active avec le système d’add-ons activé

Installation

Étape 1 : Téléverser l’add-on

Dans le panneau d’administration, allez dans Admin → Extensions → Add-ons et cliquez sur le bouton Télécharger un add-on. Sélectionnez le fichier ZIP de l’add-on : le système le décompresse automatiquement et l’add-on apparaît dans la liste des add-ons installés.

Étape 2 : Activer l’add-on

Repérez Gestion de Licences dans la liste et cliquez sur Activer. Ses migrations, ses seeders (le cas échéant) et ses permissions sont mis en place automatiquement.

Étape 3 : Configurer

Naviguez vers Admin → Licences → Paramètres pour définir votre clé API, vos préférences de format de clé et les marketplaces sur lesquelles vous vendez (voir Marketplaces). Voir Configuration.

Code d’achat (clé de licence)

Gestion de Licences est vendu comme un produit distinct : il possède donc son propre code d’achat (clé de licence) : différent du code d’achat de l’application principale et de celui de chaque autre add-on. Il vous est demandé lorsque vous activez Gestion de Licences dans Panneau d’administration → Add-ons.

Nos produits sont vendus sur trois plateformes. La manière dont vous recevez un code d’achat dépend de l’endroit où vous avez acheté le produit.

Plateforme / Marketplace Comment obtenir le code d’achat Où le retrouver
Boutique bedigit.com
Achat sur le site (Boutique)
Généré automatiquement lorsque la commande est payée, puis envoyé par e-mail, soit dans un e-mail de licence dédié, soit dans l’e-mail de confirmation de commande. Mon compte → Mes licences sur bedigit.com
Gumroad Créé dès que Gumroad nous notifie la vente, puis envoyé dans un e-mail séparé, en plus du reçu Gumroad. L’e-mail de licence, votre Bibliothèque Gumroad et Mon compte → Mes licences sur bedigit.com
Envato Market
CodeCanyon
Délivré par Envato, et non par nous, et jamais envoyé par e-mail : vous le téléchargez vous-même depuis votre compte Envato. Compte Envato → Downloads → License certificate & purchase code
Vérifiez votre dossier de spam. Pour les achats effectués sur la Boutique bedigit.com comme sur Gumroad, le code d’achat est envoyé par e-mail. Les e-mails de licence automatisés sont très souvent filtrés : si le message n’est pas dans votre boîte de réception, regardez dans votre dossier spam / courrier indésirable avant de contacter le support, et ajoutez notre adresse d’expédition à vos contacts ou à votre liste d’autorisation.

1. Boutique bedigit.com (achat sur le site)

  • Dès que le statut de paiement de la commande passe à Payée, une clé de licence est générée automatiquement pour chaque article sous licence de la commande (une clé par unité achetée : l’achat de 3 unités donne 3 clés distinctes).
  • Elle est envoyée à l’adresse e-mail utilisée pour la commande, soit dans un e-mail de licence dédié, soit dans l’e-mail de confirmation de commande. Vérifiez votre boîte de réception et votre dossier spam / courrier indésirable.
  • La clé reste disponible dans votre compte sous Mon compte → Mes licences. Les clés sont masquées dans la liste ; ouvrez la page de détail de la licence pour révéler et copier la clé complète, voir les domaines sur lesquels elle est activée, et désactiver un domaine pour libérer un emplacement d’activation.
  • La facture correspondante se trouve sous Mon compte → Mes commandes.

2. Gumroad

  • Un achat sur Gumroad génère deux e-mails distincts : le reçu Gumroad (envoyé par Gumroad, donnant accès aux fichiers) et un e-mail de clé de licence (envoyé par bedigit.com) qui contient votre code d’achat.
  • L’e-mail de clé de licence est généré dès que Gumroad nous notifie la vente : il arrive donc normalement quelques secondes après le paiement. Là encore, vérifiez votre boîte de réception et votre dossier spam / courrier indésirable.
  • Lorsque le produit Gumroad utilise la fonctionnalité de clés de licence propre à Gumroad, la même clé apparaît aussi dans votre reçu Gumroad et sous Bibliothèque → votre achat sur gumroad.com.
  • Utilisez la même adresse e-mail sur bedigit.com que sur Gumroad : vos clés sont alors liées automatiquement à votre compte et listées sous Mon compte → Mes licences, même si vous vous inscrivez après l’achat. Vous pouvez aussi ajouter une clé Gumroad manuellement depuis Mon compte → Mes licences Gumroad.

3. Envato Market (CodeCanyon)

  • Les codes d’achat Envato sont délivrés et fournis par Envato Market, jamais envoyés par e-mail par nos soins, il n’y a donc rien à chercher dans votre dossier de spam : vous récupérez le code depuis votre compte Envato.
  • Connectez-vous à votre compte Envato / CodeCanyon, ouvrez la page Downloads, repérez l’article, puis choisissez License certificate & purchase code dans le menu déroulant Download. Le code est inscrit dans ce certificat.
  • Un code d’achat Envato ressemble à 12345678-90ab-cdef-1234-567890abcdef (8-4-4-4-12 caractères). Il ne change jamais, et le renouvellement du support de l’article n’en génère pas de nouveau.
  • Article officiel Envato : Where Is My Purchase Code?
Vous avez perdu votre code d’achat ? Recherchez dans votre boîte mail (dossier de spam inclus) les termes “licence” ou “code d’achat”, puis consultez Mon compte → Mes licences sur bedigit.com pour les achats Boutique et Gumroad, ou Downloads → License certificate sur Envato. S’il est toujours introuvable, ouvrez un ticket sur notre Centre d’aide en indiquant votre numéro de commande (Boutique), l’identifiant de vente Gumroad ou l’e-mail de l’acheteur (Gumroad), ou votre nom d’utilisateur Envato et le nom de l’article (Envato).

Configuration

Tous les paramètres peuvent être configurés de deux manières :

  1. Panneau d’administration : Licences → Paramètres (stockés dans la table settings, groupe licenses)
  2. Variables d’environnement : dans .env (utilisées comme valeurs par défaut ; les paramètres admin les remplacent)
Paramètre Description Défaut
api_key Clé API requise pour tous les points de terminaison côté client. Envoyée via l’en-tête X-Api-Key ou le paramètre de requête api_key. (vide)
default_key_format Format présélectionné sur les formulaires de clé : uuid, alphanumeric, prefixed ou hmac_signed (voir Formats de clé et préfixe). alphanumeric
key_prefix Le mot de tête du format prefixed (ex. LIC dans LIC-A1B2C-D3E4F-G5H6J-K7L8M). Lettres uniquement, 10 maximum, mis en majuscules lors de la construction de la clé. Inutilisé par les trois autres formats : le champ n’est donc affiché que lorsque default_key_format vaut prefixed. LIC
default_max_activations Limite d’activation par défaut lors de la création de nouvelles clés. 1
hmac_key Clé secrète pour le format de clé signé HMAC et la vérification de signature webhook. (vide, utilise APP_KEY par défaut)
api_rate_limit Nombre maximum de requêtes API par minute par client. 3
api_daily_rate_limit Nombre maximum de requêtes API par jour par client. 50

Ancien point de terminaison de vérification Modifiable en v1.0.15

Si vous migrez depuis un système de vérification de licences existant, les logiciels que vous avez déjà publiés continuent d’appeler l’ancienne URL avec les anciens paramètres de requête. L’ancien point de terminaison répond à ces appels : vous n’avez donc pas à livrer une mise à jour à chacun de vos clients. Il ne requiert aucune clé API : les anciens clients n’en envoyaient jamais.

Le point de terminaison est désactivé par défaut : une installation neuve n’a rien avec quoi rester compatible. Activez-le avec l’interrupteur situé dans l’en-tête de la carte Configuration de l’ancien point de terminaison. Les six options se trouvent dans l’onglet Endpoint legacy de Licences → Paramètres (depuis la v1.0.17 ; auparavant dans l’onglet Points de terminaison API), et la référence de l’onglet Points de terminaison API montre l’URL et les noms de paramètres obtenus à mesure que vous saisissez. Elles peuvent aussi être définies dans .env, que les paramètres admin remplacent.

Paramètre Variable d’environnement Description Défaut
legacy_api_enabled LICENSES_LEGACY_API_ENABLED Interrupteur principal. Tant qu’il est désactivé, la route n’est pas enregistrée, le domaine dédié ci-dessous n’est pas restreint, et le chemin est exclu des règles .htaccess / de précontrôle générées. Un chemin reste nécessaire pour qu’il réponde. désactivé
legacy_api_path LICENSES_LEGACY_API_PATH L’URI que les anciens clients appellent, relative à la racine du site (ex. envato.php, verify.php, license-check). Requis tant que le point de terminaison est activé, sans lui, rien ne répond. envato.php
legacy_api_domain LICENSES_LEGACY_API_DOMAIN Un domaine dédié à l’API : toutes les pages web y sont bloquées pour qu’il ne serve jamais de contenu dupliqué, et seuls les points de terminaison API y répondent (ex. api.example.com). Laissez vide pour ne servir le point de terminaison que sur le domaine principal. (vide)
legacy_api_params.purchase_code LICENSES_LEGACY_PARAM_KEY Nom du paramètre de requête qui porte la clé de licence ou le code d’achat. purchase_code
legacy_api_params.domain LICENSES_LEGACY_PARAM_DOMAIN Nom du paramètre de requête qui porte le domaine. domain
legacy_api_params.item_id LICENSES_LEGACY_PARAM_ITEM Nom du paramètre de requête qui porte l’ID d’article du produit. item_id

Exemple : si vos anciens clients appellent https://api.example.com/verify.php?serial=...&site=..., définissez le chemin à verify.php, le domaine à api.example.com, le paramètre du code d’achat à serial et le paramètre du domaine à site. Les trois noms de paramètres doivent être différents les uns des autres ; un champ vide conserve son nom par défaut.

Vous mettez à jour depuis la v1.0.14 ou une version antérieure ? L’interrupteur est initialisé à activé sur une installation qui répondait déjà sur un ancien chemin : les logiciels de vos clients continuent ainsi de se vérifier après la mise à jour. Il n’est désactivé par défaut que sur les installations où aucun ancien chemin n’était configuré.
Modifier l’interrupteur ou le chemin reconstruit ce qui s’exécute avant Laravel. Le cache de la table des routes est vidé à l’enregistrement et, lorsque la liste de blocage .htaccess est activée, les règles Apache générées et le gardien de précontrôle sont régénérés, car tous deux filtrent sur l’ancien chemin et les noms de paramètres.

Règles de bannissement de l’ancien point de terminaison Ajouté en v1.0.17

L’onglet Règles de bannissement contient une carte par famille de points de terminaison. La seconde, Règles de bannissement de l’endpoint legacy, donne à l’ancien point de terminaison ses propres règles : la contrepartie de la carte Règles de bannissement de l’API située au-dessus, qui régit les seuls points de terminaison /api/licenses/*. Elle est masquée tant que l’ancien point de terminaison est désactivé ; activez-le depuis l’onglet Endpoint legacy et elle apparaît, avec les valeurs enregistrées :

  • les deux interrupteurs de bannissement automatique en cas de dépassement (strict, et clés/domaines non vérifiés uniquement), chacun avec ses propres seuils par minute et par jour. Les anciens appels sont comptés sur des limiteurs de débit distincts : un client qui martèle l’ancien point de terminaison ne consomme donc pas le budget de l’API non-legacy de la même IP ;
  • l’interrupteur de réponse de bannissement neutre et son message de rejet. La valeur par défaut pour l’ancien point de terminaison indique « License verification could not be completed with this version of the software. For security reasons, please update your installation to the latest release. » : un ancien appelant exécute une version obsolète de votre logiciel ; plutôt que de révéler pourquoi l’appel a été rejeté, le message lui demande donc de se mettre à jour. L’API non-legacy conserve son Request rejected. neutre (modifiable sur la carte Règles de bannissement de l’API également).

Chaque valeur de l’ancien point de terminaison suit celle de l’API tant qu’elle n’est pas définie : la mise à jour ne change donc rien. Les champs affichent les valeurs de l’API, et enregistrer l’onglet les inscrit pour l’ancien point de terminaison. Le message fait exception et possède la valeur par défaut ci-dessus. Le gardien de précontrôle intègre les paramètres de réponse des deux familles et retient celui qui correspond au chemin de la requête.

Paramètres des marketplaces

Chaque marketplace possède sa propre carte sur la page des paramètres. Les interrupteurs d’activation sont décrits dans Marketplaces.

Paramètre Marketplace Description
envato_api_token Envato Market Jeton personnel depuis build.envato.com
envato_author_username Envato Market Votre nom d’utilisateur auteur Envato
envato_purchase_code_regex Envato Market Motif que doit respecter un code d’achat (par défaut : le format UUID utilisé par Envato)
gumroad_access_token Gumroad Jeton d’accès d’une application Gumroad (utilisé par le test de connexion)
gumroad_product_ids Gumroad IDs de produits Gumroad séparés par des virgules, sur lesquels les clés sont vérifiées. Inutile lorsque l’add-on Gumroad est actif : ses produits importés sont utilisés.
gumroad_license_key_regex Gumroad Motif que doit respecter une clé de licence Gumroad
webhook_secret Webhook Secret partagé pour la vérification de signature HMAC-SHA256

Marketplaces Mis à jour en v1.0.13

Une marketplace est l’origine d’une clé de licence. Chaque clé enregistre sa marketplace, et chaque produit enregistre les marketplaces sur lesquelles il est vendu. Il en existe deux sortes :

Marketplace Sorte Origine de ses clés
Boutique (shop) Plateforme de vente Générées lorsqu’une commande de l’add-on Boutique du site est confirmée (voir Génération automatique via la boutique).
Envato Market (envato) Plateforme de vente Codes d’achat Envato, vérifiés auprès de l’API Envato lors de leur première apparition.
Gumroad (gumroad) Plateforme de vente Clés de licence Gumroad, vérifiées auprès de l’API Gumroad lors de leur première apparition.
Manuelle (manual) Interne Clés que vous créez ou générez en masse depuis le panneau d’administration. Anciennement appelée « Sur le site ».
Webhook (webhook) Interne Clés transmises par un système externe à POST /api/licenses/callback/webhook.

Une plateforme de vente est un endroit où des produits sont vendus : un produit de licence peut donc y avoir une fiche (voir Où un produit est vendu). Les marketplaces internes n’ont pas de fiches.

Activer une marketplace

Allez dans Licences → Paramètres. Chaque carte de marketplace possède un interrupteur Activer, et la carte Statut des marketplaces indique lesquelles sont actives.

Paramètre Variable d’environnement Défaut Lorsqu’elle est activée
licenses_manual_marketplace_enabled LICENSES_MANUAL_MARKETPLACE_ENABLED Activé Les clients peuvent enregistrer les clés que vous avez émises à la main.
licenses_shop_marketplace_enabled LICENSES_SHOP_MARKETPLACE_ENABLED Activé Une commande Boutique confirmée émet ses clés de licence. Nécessite l’add-on Boutique.
licenses_envato_marketplace_enabled LICENSES_ENVATO_MARKETPLACE_ENABLED Désactivé Les clés inconnues sont vérifiées auprès de l’API Envato et enregistrées lorsqu’elles sont valides. Les articles importés par l’add-on Envato sont aussi proposés comme fiches des produits de licence.
licenses_gumroad_marketplace_enabled LICENSES_GUMROAD_MARKETPLACE_ENABLED Désactivé Les clés inconnues sont vérifiées auprès de l’API Gumroad et enregistrées lorsqu’elles sont valides. Les produits importés par l’add-on Gumroad sont aussi proposés comme fiches des produits de licence.

Les interrupteurs d’activation déterminent aussi quelles sections de marketplace le formulaire produit propose, et quelles marketplaces sont annoncées aux clients comme lieux d’achat.

Renommés en v1.0.13. Ces paramètres s’appelaient auparavant licenses_insite_provider_enabled, licenses_shop_provider_enabled, licenses_envato_provider_enabled et licenses_gumroad_provider_enabled. La mise à jour les renomme en conservant leurs valeurs. Si vous les définissez dans .env, renommez aussi les variables (LICENSES_*_MARKETPLACE_ENABLED).

Variables d’environnement

Admin : Tableau de bord

Le tableau de bord (Licences → Tableau de bord) fournit un aperçu en temps réel :

  • Cartes de statistiques : Total des clés, clés actives, total des produits, activations actives
  • Répartition par statut : Nombre de clés suspendues, expirées et révoquées
  • Clés récentes : Les 10 dernières clés créées avec affichage masqué et badges de statut
  • Webhooks récents : Les 5 derniers événements webhook avec marketplace et statut

Admin : Produits

Les produits représentent le logiciel ou service faisant l’objet d’une licence. Chaque clé de licence appartient à un produit.

Créer un produit

Naviguez vers Licences → Produits → Ajouter un produit.

Champ Requis Description
name Oui Nom du produit (traduisible)
slug Non Identifiant compatible URL. Généré automatiquement à partir du nom si vide. Unique.
slug_aliases Non Autres noms que les applications clientes peuvent envoyer pour ce produit, séparés par des virgules. Peuvent être partagés avec d’autres produits. Voir Alias de slug partagés.
description Non Description du produit (traduisible, max 2000 caractères)
sku Non L’identifiant propre du produit, celui que les applications clientes envoient en premier. Doit être unique. Voir Le SKU.
version Non Version actuelle du produit (ex. 2.1.0)
is_active - Interrupteur. Les produits inactifs sont masqués des listes de sélection.

Le SKU : l’identifiant du produit Mis à jour en v1.0.13

Le SKU est l’identifiant propre du produit. Les applications, add-ons et thèmes que vous vendez l’envoient en premier lorsqu’ils vérifient un code d’achat : il doit donc être la même chaîne partout :

  • sur le produit de licence ;
  • sur le produit de la boutique sous lequel le produit de licence est vendu ;
  • dans la clé sku du addon.json de l’add-on ou du theme.json du thème (et dans la configuration de licence de l’application elle-même).

Utilisez une valeur préfixée par gamme de produits, afin que deux gammes n’entrent jamais en collision. Si vous vendez deux applications, myapp et otherapp, nommez leurs SKU myapp et otherapp, l’add-on PayPal de chacune myapp-paypal et otherapp-paypal, et un thème myapp-theme-aurora.

N’utilisez jamais un ID de marketplace comme SKU. Un ID d’article Envato ou un ID de produit Gumroad appartient à la fiche du produit sur cette marketplace (voir Où un produit est vendu), pas au SKU. La mise à jour 1.0.13 vide tous les SKU qui contenaient encore un ID Envato ou Gumroad, et donne son slug comme SKU à chaque produit qui n’en a pas.

Les boutons du champ SKU

Dans les formulaires de création et de modification de produit, le champ SKU possède deux boutons :

  • Bouton Boutique (icône boutique, avant le champ, affiché uniquement lorsque l’add-on Boutique est actif) : ouvre une liste paginée et recherchable des produits de la boutique. Cliquez sur l’un d’eux pour copier son SKU dans le champ. Un produit de la boutique sans SKU ne peut pas être sélectionné.
  • Bouton magique (après le champ) : retrouve le SKU du produit de la boutique correspondant à ce produit, ou en génère un nouveau lorsqu’il n’y a pas de correspondance (ou pas d’add-on Boutique).

Garder identiques les SKU de la boutique et de la licence

Lorsqu’un produit de licence est vendu sur la Boutique, les deux SKU sont maintenus identiques :

  • Lorsqu’un côté n’a pas de SKU, l’enregistrement de l’un ou l’autre produit copie le SKU de l’autre côté.
  • Deux SKU différents ne sont jamais écrasés. licenses:doctor les signale (sku_mismatch), et le bouton Créer / Mettre à jour le produit de licence du produit de la boutique refuse de s’exécuter jusqu’à ce que vous les aligniez.
  • Ce bouton refuse également de s’exécuter lorsque le SKU de la boutique est déjà utilisé par un autre produit de licence.

Où un produit est vendu Ajouté en v1.0.13

Un produit de licence peut être vendu sur plusieurs plateformes de vente à la fois. Chaque plateforme sur laquelle il est vendu constitue une fiche, enregistrée avec les identifiants sous lesquels cette plateforme connaît le produit. Un code d’achat provenant de n’importe laquelle de ces fiches débloque le produit.

Le formulaire produit comporte une section par plateforme de vente : Envato, Gumroad et Boutique. Une section s’ouvre d’elle-même lorsque le produit y a déjà une fiche. Sinon, cliquez sur son bouton Ajouter situé au-dessus des sections. Un bouton Ajouter n’est proposé que lorsque la marketplace est activée dans les paramètres.

Section À choisir dans le catalogue Ou saisissez les identifiants
Envato Un article importé par l’add-on Envato ID d’article Envato
Gumroad Un produit importé par l’add-on Gumroad ID de produit Gumroad, permalien court, permalien personnalisé
Boutique Un produit de l’add-on Boutique SKU du produit de la boutique
  • Lorsque l’add-on de la plateforme est installé, la section affiche un sélecteur avec recherche. Les identifiants de la fiche choisie sont enregistrés avec elle. Cliquez sur Saisir les identifiants manuellement pour les taper à la place.
  • Lorsque l’add-on de la plateforme n’est pas installé, seuls les champs d’identifiants sont affichés. L’add-on Gestion de Licences fonctionne sans les add-ons Envato et Gumroad : les identifiants saisis sont alors ce qui lui permet de reconnaître un code d’achat.
  • Vider le sélecteur (ou les champs) supprime la fiche.
  • La liste des produits affiche un badge pour chaque plateforme sur laquelle un produit est vendu, et peut être filtrée par marketplace (ou par « Vendu sur aucune marketplace »).

Les pages Liens des add-ons Envato et Gumroad modifient les mêmes fiches, depuis l’autre côté : choisissez les produits de licence que vend un article Envato ou un produit Gumroad. Une même fiche peut vendre plusieurs produits de licence (un lot).

Alias de slug partagés Mis à jour en v1.0.13

Les anciennes applications clientes identifient un produit uniquement par le nom de son répertoire (paypal, stripe…). Deux de vos gammes de produits peuvent livrer un add-on sous le même nom de répertoire : chacune des deux applications que vous vendez peut avoir son propre add-on paypal, vendu comme deux produits de licence. Si un seul d’entre eux pouvait répondre à paypal, l’acheteur de l’autre obtiendrait « License key does not belong to this product. »

Un alias de slug peut donc être attribué à plusieurs produits. Ajoutez paypal aux alias des deux produits PayPal : un ancien client qui envoie paypal vérifie alors une clé de l’un ou de l’autre. L’API contrôle toujours le produit propre à la clé : une clé du premier produit ne débloque donc rien d’autre.

  • Le slug principal reste unique.
  • Un alias ne peut apparaître qu’une seule fois dans la liste d’un même produit. Un alias identique au slug du produit est ignoré.

Comment l’API reconnaît un produit

Une application cliente envoie le paramètre product avec le code d’achat. Les applications clientes actuelles essaient, dans cet ordre, jusqu’à ce que l’une soit acceptée :

  1. le SKU du produit ;
  2. les ID de marketplace du produit dont le format correspond au code (l’ID d’article Envato pour un code d’achat Envato, l’ID Gumroad pour une clé Gumroad, le SKU boutique pour une clé boutique) ;
  3. le slug (nom du répertoire).

Les anciens clients n’envoient que le slug, et continuent de fonctionner. Côté serveur, le produit de la clé est accepté lorsque la valeur est, dans cet ordre :

  1. son SKU ;
  2. l’un de ses alias de slug ;
  3. l’ancien item_id enregistré dans ses métadonnées ;
  4. un identifiant de l’une de ses fiches : ID d’article Envato, ID de produit Gumroad ou permaliens, SKU boutique ;
  5. son slug principal.

Sinon, l’API répond « License key does not belong to this product. »

Chacune de ces valeurs est acceptée : ce que vous envoyez ne change donc que l’étape à laquelle la correspondance se produit :

Ce que le client envoie Ce qui se passe
product=<SKU> Correspondance à l’étape 1, le chemin le plus court. C’est ce que les applications clientes actuelles envoient en premier.
product=<alias slug> Correspondance à l’étape 2, sur la liste d’alias du produit.
product=<marketplace ID> Correspondance à l’étape 4 : un ID d’article Envato, un ID de produit Gumroad, un permalien personnalisé ou court Gumroad, ou le SKU d’un produit de la boutique : à condition que le produit possède une fiche portant cet identifiant. S’il n’a pas de fiche sur cette marketplace, rien ne correspond et l’appel est rejeté.
product=<slug> Correspondance à l’étape 5, la dernière. Cela fonctionne toujours, mais toutes les étapes précédentes sont essayées d’abord.
Aucun product La vérification du produit est ignorée : la clé est validée dès lors qu’elle existe, qu’elle est active et que sa limite d’activation le permet. La réponse nomme quand même le produit réel, de sorte qu’un client peut la comparer lui-même. Les anciens logiciels qui envoient leur ID d’article sous un autre nom de paramètre, comme item_id=, relèvent de ce cas sur ce point de terminaison, ce paramètre n’est lu que par l’ancien point de terminaison de vérification, qui le résout en produit et le vérifie bel et bien.
Deux points à garder en tête.
  • Un alias partagé est délibérément ambigu. Le contrôle demande seulement si le produit propre à la clé porte la valeur : un alias détenu par plusieurs produits (paypal sur l’add-on PayPal de deux applications différentes) permet donc à une clé de l’un ou de l’autre de se vérifier. C’est ce qui répare les anciens clients, et cela signifie aussi que l’alias seul ne prouve pas de quel produit l’appelant voulait parler.
  • La correspondance est exacte. La comparaison est sensible à la casse et un espace autour de la valeur la fait échouer : envoyez donc la valeur exactement telle qu’elle est enregistrée sur le produit.

Intégrations avec les add-ons

Les produits de licence se connectent aux autres add-ons via des boutons passerelle en un clic. Chaque bouton n’apparaît que lorsque l’add-on correspondant est actif et que vous disposez de la permission requise.

  • Importer depuis l’add-on Envato et Importer depuis l’add-on Gumroad (barre d’outils de la page, lorsque cet add-on est actif) : créent ou mettent à jour des produits de licence à partir de vos articles Envato ou produits Gumroad importés, et enregistrent chacun d’eux comme fiche du produit. Leur équivalent article par article, un bouton Créer / Mettre à jour le produit de licence, se trouve sur chaque article des add-ons Envato et Gumroad. Un article est rattaché à son produit existant d’abord par sa fiche, puis par slug ou par nom : il n’obtient donc jamais deux produits. Les produits importés sont créés sans SKU : définissez le SKU vous-même.
  • Créer / Mettre à jour le département de support (action de ligne + pied de la fenêtre de modification, lorsque l’add-on HelpDesk est actif) : crée ou met à jour un département d’assistance pour le produit et en réserve l’accès aux détenteurs d’une licence. Voir la documentation de l’add-on HelpDesk pour les détails. Vous pouvez cliquer plusieurs fois sans risque : le même département est mis à jour au lieu de créer des doublons.
  • Créer / Mettre à jour le produit de licence depuis un produit numérique de la Boutique : le sens inverse, ce bouton se trouve dans l’administration du produit de la boutique, crée ou met à jour le produit de licence, et enregistre le produit de la boutique comme sa fiche Boutique. Le produit de licence reçoit le SKU du produit de la boutique (voir synchronisation des SKU).
Pas de doublons. Chaque passerelle est idempotente : la relancer retrouve l’enregistrement existant (par sa fiche, son SKU, son slug ou son nom) et le met à jour au lieu d’en créer un second.

Admin : Clés de licence

Créer une clé

Naviguez vers Licences → Clés de licence → Ajouter une clé.

Champ Requis Description
product Oui Le produit auquel cette clé appartient
key Non Chaîne de clé de licence. Laissez vide pour générer automatiquement à l’enregistrement, ou cliquez sur le bouton Générer (icône baguette) placé devant le champ pour en générer une tout de suite (voir ci-dessous).
key_format Non Format utilisé pour générer la clé : aussi bien par le bouton Générer qu’à l’enregistrement (voir Formats de clé et préfixe)
license_type Oui Standard, Étendue, Essai ou À vie
status Oui Active, Suspendue, Expirée ou Révoquée
expires_at Non Date d’expiration. Laissez vide pour les clés sans expiration.
supported_until Non Date de fin de support. Distincte de l’expiration de licence : suit la fin de la période de support du client (ex. fenêtre de support de 6 mois Envato).
max_activations Oui Nombre de domaines/machines sur lesquels cette clé peut être activée simultanément
marketplace Oui L’origine de la clé : manual, shop, envato, gumroad ou webhook (voir Marketplaces)
marketplace_reference Non ID de commande externe, code d’achat, etc.
assigned_user Non Lier optionnellement à un compte utilisateur
notes Non Notes internes (non exposées via l’API)

Générer la clé à la main

Le champ Clé porte un bouton Générer (une icône baguette) placé devant lui. Un clic remplit le champ immédiatement avec une nouvelle clé construite dans le Format de clé sélectionné juste en dessous : vous pouvez donc lire la clé, la copier, ou changer de format et recommencer avant d’enregistrer. Le champ reste modifiable : vous pouvez toujours saisir votre propre clé par-dessus.

Les deux façons d’obtenir une clé aboutissent au même résultat :

  • Laisser le champ vide → la clé est générée à l’enregistrement du formulaire, dans le format sélectionné.
  • Cliquer sur le bouton Générer → la même clé est générée immédiatement et affichée dans le champ, puis enregistrée telle quelle.

Le bouton demande la clé au serveur plutôt que de la construire dans votre navigateur : la clé générée est donc toujours une vraie clé. Le format prefixed reçoit le préfixe configuré dans Réglages → Génération de clés, le format hmac_signed reçoit une véritable signature, et le résultat est vérifié face aux clés existantes pour qu’il ne puisse jamais entrer en collision avec une clé déjà émise.

Astuce : Cliquer de nouveau sur le bouton remplace ce qui se trouve dans le champ, rien n’est enregistré tant que vous n’avez pas soumis le formulaire, appuyez donc autant de fois que vous le souhaitez. Changez d’abord le Format de clé si vous voulez une autre forme.
Remarque : La chaîne de clé ne peut pas être modifiée après la création. Choisissez votre format avec soin, ou laissez le système la générer automatiquement.

Formats de clé et préfixe

Toute clé générée suit l’un des quatre formats. Le format est choisi clé par clé sur les formulaires de création et de génération en masse ; celui qui y est présélectionné vient de Réglages → Génération de clés → Format de clé par défaut.

Format Forme Exemple
uuid Un UUID v4 standard (36 caractères, hexadécimal en minuscules). 550e8400-e29b-41d4-a716-446655440000
alphanumeric Cinq groupes de cinq lettres majuscules et chiffres, séparés par des tirets. A1B2C-D3E4F-G5H6J-K7L8M-N9P0Q
prefixed Votre propre préfixe, puis quatre groupes de cinq lettres majuscules et chiffres. LIC-A1B2C-D3E4F-G5H6J-K7L8M
hmac_signed Deux groupes de cinq caractères, un point, et une signature de 12 caractères calculée avec la clé HMAC. A1B2C-D3E4F.a3f2b1c4d5e6

Le préfixe de clé

Le champ Préfixe de clé (Réglages → Génération de clés) est le mot de tête du format prefixed : le LIC de LIC-A1B2C-D3E4F-G5H6J-K7L8M. Utilisez-le pour rendre vos clés reconnaissables au premier coup d’œil, par exemple votre marque ou la gamme de produits à laquelle elles appartiennent.

  • Il est utilisé uniquement par le format prefixed. Les clés générées en uuid, alphanumeric ou hmac_signed l’ignorent totalement.
  • Lettres uniquement, jusqu’à 10 caractères. Il est mis en majuscules lors de la construction de la clé : acme produit donc ACME-….
  • Parce qu’il n’est utile qu’à ce seul format, le champ n’est affiché que lorsque Format de clé par défaut vaut Préfixé. Votre préfixe est conservé pendant qu’il est masqué : revenez à ce format et la valeur enregistrée est toujours là.
  • Il s’applique à toutes les clés prefixed générées ensuite : depuis le formulaire de création, le bouton Générer, la génération en masse, et la génération automatique lors d’une commande boutique.
Changez le préfixe avant de commencer à vendre, pas après. Le préfixe fait aussi partie du motif que l’API utilise pour reconnaître une clé au format prefixed. Si vous le changez une fois que des clés prefixed sont entre les mains de vos clients, ces anciennes clés ne correspondent plus au motif et sont rejetées par verify / activate avec « Le format de la clé de licence ne correspond à aucune marketplace activée. » : avant même que la clé ne soit recherchée. Si vous devez le changer, générez des clés de remplacement pour les clients qui détiennent les anciennes.

Opérations en masse

Génération en masse

Naviguez vers Clés de licence → Génération en masse pour créer jusqu’à 1 000 clés en une fois. Sélectionnez le produit, le format, le type de licence, le nombre maximum d’activations et la date d’expiration optionnelle.

Suppression en masse

Sur la page de liste des clés, sélectionnez plusieurs clés avec les cases à cocher et cliquez sur Supprimer la sélection.

Export CSV

Cliquez sur Exporter en CSV sur la page de liste des clés. Permet le filtrage par produit et statut avant l’export.

Actions de cycle de vie

Action Effet
Suspendre Définit le statut à suspended. La clé échoue à la vérification mais peut être réactivée ultérieurement. Les activations existantes restent mais ne sont pas fonctionnelles.
Révoquer Définit le statut à revoked et désactive toutes les activations actives. Cela est irréversible en pratique.
Réactiver Redéfinit le statut à active. La clé redevient valide (si non expirée).

Admin : Activations

Consultez toutes les activations d’une clé spécifique en cliquant sur Activations sur la page de détail de la clé, ou en naviguant vers /admin/licenses/keys/{id}/activations.

Chaque enregistrement d’activation affiche :

  • Domaine (si fourni), avec un badge Local pour les domaines locaux/de développement
  • Identifiant machine (si fourni)
  • Version Ajouté en v1.0.17, la version de l’application, de l’add-on ou du thème que le client a remontée avec son paramètre version, rafraîchie à chaque appel verify / activate ultérieur : un audit indique donc quelles installations tournent encore sur une version obsolète. Les versions de Larapen, LaraClassifier et JobClass qui incluent cette évolution l’envoient pour l’application elle-même et pour chaque add-on ou thème qu’elles activent ; les clients plus anciens la laissent vide. Le champ de recherche la prend en compte, et le journal API l’affiche à côté du produit de chaque appel.
  • Adresse IP
  • Agent utilisateur
  • Date d’activation
  • Statut Actif/Désactivé

Les administrateurs peuvent manuellement désactiver toute activation active pour libérer un emplacement pour le client.

Lorsque « Enregistrer les activations de domaines locaux » est activé dans les paramètres de contournement des domaines locaux, les activations locales apparaissent dans la liste mais ne comptent pas dans la limite max_activations de la clé. Un bouton Supprimer les activations locales permet de supprimer en masse tous les enregistrements d’activation locale pour une clé. La page d’index des clés de licence fournit un filtre pour afficher uniquement les clés avec des activations locales.

Admin : Paramètres

La page de paramètres (Licences → Paramètres) est organisée en sections :

  • Configuration API : pour les points de terminaison /api/licenses/*, l’interrupteur de l’API, la clé API, le jeton de contournement de la limite de débit et l’exemption en mode maintenance
  • Règles de bannissement (nommé Liste de blocage avant la v1.0.17, et Liste de blocage .htaccess auparavant) : une carte par famille de points de terminaison : Règles de bannissement de l’API et Règles de bannissement de l’endpoint legacy, chacune avec ses deux interrupteurs de bannissement automatique en cas de dépassement, leurs seuils par minute et par jour et la réponse de bannissement neutre avec son message de rejet : suivies de l’interrupteur de bannissement d’IP, de l’exemption de bannissement de l’API non-legacy, des paramètres de requête requis (bloquer les appels API n’envoyant aucune clé de licence, et/ou aucun domaine, comme s’ils étaient bannis) et de la liste de blocage .htaccess, activation/désactivation, stratégie, nombre maximum d’entrées par liste (500 par défaut), boutons Régénérer/Supprimer/Afficher
  • Endpoint legacy : la configuration de l’ancien point de terminaison : interrupteur, chemin, domaine dédié et noms de paramètres. Ses règles de bannissement se trouvent dans l’onglet Règles de bannissement, à côté de celles de l’API
  • Génération de clés : format de clé par défaut, préfixe de clé (affiché uniquement tant que le format par défaut est Préfixé, puisque aucun autre format ne l’utilise), nombre maximum d’activations par défaut et clé HMAC
  • Domaines : la manière dont le domaine envoyé par un client est comparé aux activations enregistrées : « Traiter www. comme le même domaine » (activé par défaut : www.toto.com et toto.com partagent un même emplacement d’activation) et « Autoriser les sous-domaines des domaines activés » (désactivé par défaut : lorsqu’il est activé, toto.com, fr.toto.com et de.toto.com partagent une même activation, quel que soit celui qui a été activé en premier), ainsi que le contournement des domaines locaux : activer/désactiver le contournement, interrupteur d’enregistrement des activations locales et motifs de domaines
  • Places de marché : une carte pour chacune des marketplaces Manuelle, Boutique, Envato Market et Gumroad, avec son interrupteur Activer et ses identifiants (voir Marketplaces)
  • Marketplace Webhook : secret webhook et affichage de l’URL
  • Cache : activer/désactiver la mise en cache (TTL par défaut : 24 heures, max 7 jours) + bouton Vider le cache des licences
  • Journalisation des appels API : activer/désactiver, durée de rétention (en jours), plafond optionnel du nombre d’entrées
  • Points de terminaison API : la référence de chaque point de terminaison auquel l’add-on répond, sa méthode HTTP, son URL complète (avec un bouton de copie), s’il attend l’en-tête X-Api-Key, et chaque paramètre avec son état requis/optionnel ; l’entrée de l’ancien point de terminaison reflète l’onglet Endpoint legacy à mesure que vous saisissez

Admin : Journaux de webhooks

Tous les événements webhook entrants sont journalisés avec leur marketplace, type d’événement, données brutes, données de réponse, statut (Succès / Échec / Ignoré) et messages d’erreur éventuels. Naviguez vers Licences → Journaux de webhooks pour consulter. Filtrez par marketplace ou statut.

Admin : Journaux API Ajouté en v1.0.1

Chaque appel API entrant vers verify, activate, deactivate, callback et l’ancien point de terminaison est enregistré dans la table licenses_api_logs à des fins de débogage et d’audit. Naviguez vers Licences → Journaux API.

Ce qui est journalisé

  • Point de terminaison (nom de route), méthode HTTP, code de statut, indicateur de succès
  • Adresse IP, agent utilisateur, durée (ms)
  • Charge utile complète de la requête (query + corps), les champs sensibles (api_key, password, token, secret, authorization) étant automatiquement masqués par [REDACTED]
  • Charge utile de la réponse (tronquée à max_body_size si elle est trop grande)
  • Message d’erreur extrait du corps de la réponse lorsque l’appel n’est pas un succès fonctionnel
  • Clé API masquée (format abcd...wxyz) : la clé complète n’est jamais stockée

Filtres & fonctionnalités

  • Filtrer par point de terminaison, statut (succès/échec), plage de dates, domaine ou clé
  • Cartes de statistiques « Réussis / Échoués » en haut de la page
  • Fenêtre de détails par ligne avec le JSON complet de la requête/réponse, des actions de bannissement/débannissement, des icônes de filtre rapide et un lien « Ouvrir l’URL de vérification »
  • Actions de suppression en masse, « Tout effacer » et « Purger les anciens »

Regrouper les appels Ajouté en v1.0.16

Une seule action du client peut déclencher plusieurs appels d’API. L’activation d’un add-on payant avec un code d’achat en est le cas le plus clair : le client vérifie ce même code face à chaque identifiant auquel le produit répond (son SKU d’abord, puis les identifiants de marketplace dont le format correspond à la clé, puis son slug) et s’arrête au premier qui le reconnaît. Une seule activation remplit donc le journal de jusqu’à quatre lignes presque identiques, à quelques secondes d’intervalle.

Le commutateur Regrouper les appels de la barre de filtres les replie ensemble : une entrée par action du client et par produit sur lequel les appels ont finalement porté. Une entrée affiche le résultat de son dernier appel et un badge comptant les appels qu’elle replie ; en la dépliant, chaque appel est listé avec l’identifiant envoyé, nommé pour ce qu’il est (SKU, ID Gumroad, SKU boutique, Slug), son statut, son erreur et ses propres actions. Deux entrées pour une seule activation signifient généralement que les identifiants n’ont pas tous abouti au même produit, il vaut la peine de vérifier les alias de slug du produit.

Les appels sont reliés entre eux par clé, appelant (domaine ou identifiant machine), IP et point de terminaison, dans une fenêtre de api_log.correlation_window_seconds (120 par défaut). Augmentez-la pour les clients lents, diminuez-la pour séparer les entrées plus volontiers. Le commutateur ne change que l’affichage : chaque appel reste une ligne à part entière dans le tableau, et désactiver le commutateur les réaffiche tous.

Rétention & nettoyage

  • La tâche planifiée licenses:prune-api-logs s’exécute quotidiennement et supprime les journaux plus anciens que la durée de rétention configurée (30 jours par défaut).
  • Plafond optionnel « Nombre maximum d’entrées » : lorsqu’il est activé, les journaux les plus anciens sont supprimés dès que la table dépasse la taille configurée. Appliqué aussi de façon probabiliste (~1 % des insertions) en temps réel.

Ce qui n’est PAS journalisé (pour protéger les performances de la base de données)

  • Requêtes bannies (403) : lorsqu’une requête est rejetée par le middleware comme IP/clé/domaine banni, aucune ligne de journal n’est écrite : la détection des bannissements est une simple lecture du cache, sans aucune activité en base.
  • Dépassements de limite de débit (429) et échecs de validation (422) : seule la première occurrence par combinaison clé+domaine+machine_id est journalisée dans une fenêtre de 5 minutes. Cela évite de saturer la table de journaux lorsque des milliers d’IP différentes frappent la même clé.

Admin : Liste de blocage (bannissements) Ajouté en v1.0.1/1.0.2

La liste de blocage permet aux administrateurs de bloquer le trafic abusif à trois niveaux. Les contrôles s’exécutent dans le middleware CheckBannedKey, appliqué à toutes les routes API (non-legacy + anciennes). Toutes les recherches de bannissement sont servies depuis le cache, sans aucune requête en base.

Naviguez vers Licences → Liste de blocage, la page comporte trois onglets : Clés bannies, Domaines bannis, IP bannies. Chaque onglet possède un champ de recherche et une fenêtre « Bannir un... ». L’onglet IP bannies n’apparaît que lorsque le bannissement d’IP est activé (il est désactivé par défaut).

Clés bannies

Bloquez une clé de licence ou un code d’achat Envato précis. Toute requête API ultérieure portant cette clé dans key ou dans l’ancien paramètre configuré (par défaut : purchase_code) renvoie un HTTP 403 avec "error": "key_banned".

Domaines bannis

Bloquez une valeur de domaine précise. Toute requête portant ce domaine dans le paramètre domain (API non-legacy ou nom personnalisé de l’ancienne API) renvoie un HTTP 403 avec "error": "domain_banned". La comparaison est insensible à la casse.

IP bannies

Bloquez une IP source précise. Évaluée avant les contrôles de clé/domaine. Renvoie un HTTP 403 avec "error": "ip_banned". Nécessite que l’option bannissement d’IP ci-dessous soit activée.

Interrupteur de bannissement d’IP Ajouté en v1.0.9

Un interrupteur principal pour l’axe IP de la liste de blocage, sous Paramètres → Règles de bannissement. Il est désactivé par défaut, car une IP abusive est souvent une adresse partagée ou NAT : la bannir peut exclure des clients qui n’ont rien à voir.

Tant qu’il est désactivé :

  • Aucune requête n’est jamais rejetée à cause de son IP source : le middleware ignore entièrement le contrôle d’IP
  • Aucune IP n’est écrite dans les règles .htaccess générées ni dans les fichiers de précontrôle (ils sont réécrits lorsque vous basculez l’interrupteur)
  • Le bannissement automatique en cas de dépassement de la limite de débit ne se rabat jamais sur le bannissement d’une IP
  • L’onglet IP bannies est masqué, ainsi que les actions de bannissement/débannissement d’IP dans les journaux API
Les bannissements existants ne sont jamais supprimés : ils restent dans licenses_banned_ips et sont de nouveau appliqués dès que l’option est réactivée.

Les règles .htaccess et les fichiers de précontrôle sont des instantanés générés : enregistrer les paramètres les réconcilie donc avec ce que disent désormais les interrupteurs. Ils sont régénérés lorsque l’interrupteur de bannissement d’IP bascule alors que la liste de blocage est activée, et une liste de blocage restée en place après la désactivation de l’option est supprimée (les règles générées auparavant continueraient sinon de rejeter les IP bannies avant l’exécution de PHP). Si ces fichiers ne peuvent pas être écrits, l’enregistrement signale un avertissement au lieu d’échouer silencieusement.

Chaque bannissement peut inclure un motif optionnel (jusqu’à 2000 caractères) et porte le nom de l’administrateur qui l’a effectué. Les bannissements peuvent être effectués depuis la page de liste de blocage ou directement depuis la fenêtre de détails des journaux API (boutons en bas de la fenêtre).

Paramètres de requête requis Ajouté en v1.0.12

Deux interrupteurs sous Paramètres → Règles de bannissement → Paramètres de requête requis, tous deux désactivés par défaut :

  • Bloquer les requêtes sans clé de licence : rejette les appels verify / activate / deactivate et les anciens appels qui n’envoient aucun paramètre key (ou l’ancien paramètre de code d’achat). De tels appels ne pourraient de toute façon qu’échouer à la validation : il s’agit donc presque toujours de sondes, de scanners ou de clients mal configurés.
  • Bloquer les requêtes sans domaine : rejette les appels qui n’envoient aucun paramètre domain (ou l’ancien paramètre de domaine).

Un appel rejeté est traité exactement comme un appel banni : même HTTP 403, même charge utile (la réponse générique qui ne révèle rien lorsque cette option est activée, sinon key_missing / domain_missing), et aucune ligne dans les journaux API. La règle est appliquée à chaque couche de la liste de blocage :

  • toujours par le middleware PHP CheckBannedKey ;
  • lorsque la liste de blocage .htaccess est activée, également avant le chargement de Laravel (sous forme de règles Apache en mode .htaccess, ou à l’intérieur du gardien public/licenses.php en mode précontrôle) de sorte que les appels n’atteignent jamais l’application. Enregistrer les paramètres régénère automatiquement les règles ; le blocage est écrit même lorsqu’aucune IP, aucun domaine et aucune clé n’est banni.
Règle de domaine et clients de bureau : les clients qui s’identifient uniquement par machine_id n’envoient aucun domaine : ils sont donc rejetés eux aussi dès que l’interrupteur de domaine est activé. Laissez-le désactivé si vous licenciez des logiciels de bureau.
En mode .htaccess, Apache ne peut inspecter que la chaîne de requête : les règles s’appliquent donc aux requêtes GET au niveau d’Apache ; un corps POST (activate / deactivate) est toujours contrôlé par le middleware PHP. Le gardien de précontrôle contrôle chaque requête, y compris les corps JSON. Le point de terminaison de callback webhook n’est jamais affecté.

Exemption de bannissement de l’API non-legacy Ajouté en v1.0.17

L’interrupteur Ne jamais bannir les appelants de l’API non-legacy, sous Paramètres → Règles de bannissement, désactivé par défaut. Tant qu’il est activé, un appel à /api/licenses/verify, /activate ou /deactivate :

  • n’est jamais banni automatiquement, quelle que soit la limite de débit qu’il déclenche ;
  • n’est jamais rejeté par un bannissement : les contrôles d’IP, de clé et de domaine bannis le laissent passer ;
  • lève tout bannissement déjà enregistré sur la clé, le domaine ou l’IP qu’il porte, dès son arrivée (un bannissement portant sur un autre hôte du même domaine enregistrable qui le couvre, sous la politique Autoriser les sous-domaines, est levé lui aussi). Les bannissements effectués à la main depuis la page Liste de blocage sont levés de la même manière.

Seul l’ancien point de terminaison continue de bannir et d’appliquer les bannissements. L’option est destinée aux installations où l’API non-legacy n’est appelée que par des applications clientes connues (chacune envoie l’en-tête X-Api-Key) tandis que l’ancien point de terminaison est celui exposé aux scanners.

Les règles de paramètres de requête requis ne sont pas des bannissements et s’appliquent toujours à tous les points de terminaison. Tant que la liste de blocage .htaccess est activée, les règles de bannissement générées se limitent au chemin de l’ancien point de terminaison (aucune n’est écrite lorsque celui-ci est désactivé) et le gardien de précontrôle ignore les contrôles de bannissement pour les points de terminaison non-legacy ; enregistrer les paramètres régénère les deux, et un bannissement levé met une régénération en file d’attente comme le fait un bannissement automatique.

Bannissement automatique en cas de dépassement de la limite de débit Ajouté en v1.0.2

Deux interrupteurs par famille de points de terminaison, tous deux dans l’onglet Paramètres → Règles de bannissement : la carte Règles de bannissement de l’API pour l’API non-legacy, et la carte Règles de bannissement de l’endpoint legacy pour l’ancien point de terminaison (depuis la v1.0.17, avec ses propres seuils). Lorsqu’ils sont activés, toute requête qui dépasse la limite par minute ou par jour correspondante crée automatiquement un enregistrement de bannissement :

  1. Si la requête inclut un domaine → le domaine est banni
  2. Si la requête inclut une clé/purchase_code → la clé est bannie
  3. Si ni domaine, ni clé, ni machine_id n’est présent → l’IP est bannie
  4. Si la liste de blocage .htaccess est activée, les règles Apache sont régénérées automatiquement

Liste de blocage .htaccess Ajouté en v1.0.2

Une défense optionnelle au niveau d’Apache. Les requêtes bloquées renvoient un 403 avant même que PHP ne soit chargé : zéro CPU, zéro mémoire, zéro base de données. Essentiel lorsque le trafic abusif est suffisant pour saturer les workers PHP-FPM.

Configurez sous Paramètres → Règles de bannissement :

  • Interrupteur Activer / Désactiver
  • Stratégie de blocage (deux modes, choisissez selon le nombre de bannissements dont vous disposez) :
    • Règles Apache .htaccess : des règles regex écrites directement dans public/.htaccess. Le plus rapide pour de petites listes (<1000 bannissements). Apache réanalyse le .htaccess à chaque requête : les performances se dégradent donc à grande échelle.
    • Fichier de précontrôle PHP (recommandé pour les grandes listes) : déploie un petit gardien public/precheck.php qui charge des fichiers de tableaux PHP compilés et effectue des recherches de hachage en O(1). Monte à plus de 100 000 entrées sans perte de performance grâce à OPcache. Légèrement plus lent que .htaccess pour de très petites listes, mais radicalement plus rapide au-delà de 1 000 entrées.
  • Nombre maximum d’entrées par liste : plafond du nombre de bannissements écrits (htaccess : 10-5000, précontrôle : 100-1 000 000). Les entrées au-delà du plafond restent appliquées par le middleware PHP.
  • Régénérer les règles : lit les bannissements actuels et réécrit les fichiers de liste de blocage
  • Supprimer les règles : retire le bloc .htaccess et supprime les éventuels fichiers de précontrôle
  • Afficher le contenu du .htaccess : ouvre une fenêtre affichant le contenu actuel du fichier
Quel mode choisir ? Commencez par les règles .htaccess (plus simples). Passez au fichier de précontrôle PHP si vous accumulez plus de ~1000 bannissements ou si vous constatez un ralentissement du chargement des pages. Le changement est sans risque : cliquer sur Régénérer nettoie automatiquement les artefacts du mode précédent.
Avertissement de dépassement : si une liste dépasse le plafond d’entrées, une alerte jaune apparaît sur la page des paramètres avec le nombre d’entrées écrites et celui des entrées gérées uniquement par PHP. Pour les cas extrêmes (des millions de bannissements), envisagez de déplacer le bannissement d’IP vers iptables/ipset ou vers un CDN/WAF (Cloudflare).

Jeton de contournement de la limite de débit

Un jeton secret optionnel configuré sous Paramètres → Configuration API. Lorsqu’il est présent sous la forme ?bypass_token=... (ou dans l’en-tête X-Bypass-Token) et qu’il correspond à la valeur enregistrée, le limiteur de débit renvoie Limit::none() : utilisé par l’administrateur pour retester des requêtes limitées. Les entrées de journal limitées en débit utilisent automatiquement, dans la fenêtre des journaux API, une URL à laquelle le jeton de contournement est ajouté.

Admin : Cache Ajouté en v1.0.1

Toutes les lectures en base du chemin critique de l’add-on (findByKey, verify, getStats, getActiveProducts, listes d’IP/domaines/clés bannis, etc.) sont servies depuis un cache centralisé (LicenseCacheService). La vérification API reste ainsi exempte de requêtes en base une fois le cache chaud.

  • TTL par défaut : 24 heures (configurable de 1 à 168 heures depuis les Paramètres)
  • Invalidation automatique : toute écriture sur une clé de licence, un produit, une activation ou un enregistrement banni vide l’intégralité du cache des licences via le patron observateur
  • Bouton de vidage du cache : vide le cache des licences sans affecter les autres caches du système
  • Les résultats négatifs ne sont PAS mis en cache : findByKey/verify ne mettent en cache que les clés valides, les résultats « introuvable » ne sont jamais mis en cache, de sorte qu’une clé créée plus tard (par la marketplace Envato ou Gumroad, ou par un administrateur) est trouvée immédiatement

Mise à jour

Il existe deux façons de mettre à jour cet add-on : via le panneau d’administration (recommandé) ou en remplaçant manuellement les fichiers.

Méthode 1 : Téléversement depuis le panneau d’administration (recommandé)

  1. Téléchargez le dernier fichier .zip de cet add-on.
  2. Allez dans Panneau d’administration → Add-ons et cliquez sur le bouton Téléverser.
  3. Sélectionnez ou glissez le fichier .zip dans la zone de téléversement.
  4. Une boîte de confirmation affiche les numéros de version actuel et nouveau. Cliquez sur Remplacer pour continuer.
  5. Allez dans Panneau d’administration → Mise à jour du système (/admin/update) pour appliquer les migrations de base de données en attente.

Méthode 2 : Remplacement manuel des fichiers

Étape 1 : Remplacer les fichiers

Remplacez le répertoire de l’add-on par la nouvelle version (ou faites un pull de la dernière version si vous utilisez un lien symbolique vers un dépôt Git).

Étape 2 : Exécuter les migrations

Les nouvelles migrations sont automatiquement détectées. L’add-on utilise des migrations horodatées qui ne s’exécutent qu’une seule fois.

Étape 3 : Vider les caches

php artisan config:clear
php artisan route:clear
php artisan view:clear

Étape 4 : Vérifier

Visitez Licences → Tableau de bord pour confirmer que tout se charge correctement. Vérifiez la page Paramètres pour découvrir les nouvelles options de configuration introduites par la mise à jour.

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

Mise à jour vers la v1.0.13 : ordre des mises à jour Action requise

La version 1.0.13 déplace chaque lien « le produit X est vendu sur la plateforme Y » dans l’add-on Gestion de Licences. Les add-ons Envato et Gumroad ont changé avec elle. Appliquez les mises à jour dans cet ordre :

  1. Gestion de Licences 1.0.13 d’abord. Sa mise à jour copie dans les nouvelles fiches les liens encore conservés par la colonne du produit de la boutique, par les tables de liens Envato et Gumroad et par les métadonnées du produit, et renomme les paramètres de marketplace.
  2. Ensuite Envato 1.0.6 et Gumroad 1.0.3. Ils copient les liens restants, puis suppriment leurs propres tables de liens (envato_item_links, gumroad_product_links). Ils ne les suppriment que lorsque les tables de Gestion de Licences existent.

Après les mises à jour :

  • Renommez toute variable LICENSES_*_PROVIDER_ENABLED de .env en LICENSES_*_MARKETPLACE_ENABLED (celle dite insite devient LICENSES_MANUAL_MARKETPLACE_ENABLED).
  • Vérifiez le SKU de vos produits : les SKU qui contenaient un ID Envato ou Gumroad ont été vidés, et les produits sans SKU ont reçu leur slug (voir Le SKU).
  • Exécutez php artisan licenses:doctor et corrigez ce qu’il signale (voir Audit des liens).

Audit des liens (licenses:doctor) Mis à jour en v1.0.13

Une fiche détermine qui obtient l’accès : un code d’achat qui en provient débloque le produit de licence et tout ce qui est réservé derrière lui. La commande licenses:doctor liste les liens qui semblent erronés. Elle ne modifie rien.

php artisan licenses:doctor
ContrôleGravitéSignification
title_mismatchAvertissementLa fiche est vendue sous un autre titre que le produit. Il a été renommé, ou la fiche n’est pas la bonne.
source_without_linkAvertissementLe produit a été importé depuis une plateforme de vente mais n’y possède pas de fiche : les achats qui y sont effectués ne peuvent donc pas lui être rattachés.
orphan_linkErreurLa fiche pointe vers un produit de licence ou vers une ligne de catalogue de plateforme qui n’existe plus.
shared_listingAvertissementUne même fiche vend plusieurs produits : un seul code d’achat les débloque tous.
entity_unreachable_from_storeAvertissementUn département de support, une collection de base de connaissances ou une catégorie de forum à accès réservé est fermé aux acheteurs d’une plateforme de vente : aucun de ses produits n’y est vendu.
store_not_wiredAvertissementUne plateforme de vente est ouverte aux clients mais aucun produit n’y possède de fiche : toutes les entités à accès réservé sont donc fermées à ses acheteurs.
sku_mismatchAvertissementUn produit de la boutique et son produit de licence portent deux SKU différents.
sku_missingAvertissementUn produit est vendu mais n’a pas de SKU. Donnez-lui le SKU déclaré par son addon.json / theme.json.

Options

  • --threshold= : similarité de titre (%) en dessous de laquelle une fiche est signalée (60 par défaut)
  • --errors-only : ne signaler que les constats certainement cassés
  • --acknowledge : parcourir les constats et faire taire ceux que vous confirmez comme intentionnels
  • --include-acknowledged : afficher aussi les constats mis en sourdine
  • --forget : parcourir les constats mis en sourdine et rétablir ceux que vous choisissez
  • --strict : sortir avec un code d’erreur également en cas d’avertissements
  • --json : produire les constats en JSON

Fusionner deux produits

Lorsque le même logiciel a été importé une fois par plateforme de vente, vous obtenez un produit par plateforme. Fusionnez-les pour qu’un seul produit porte toutes les fiches :

php artisan licenses:merge-products {from} {into} --dry-run

{from} et {into} sont des ID ou des slugs de produits. La commande déplace les clés, les liens d’entités à accès réservé et les fiches de {from} vers {into}, puis supprime {from}. Retirez --dry-run pour l’appliquer (--force ignore la confirmation).

Page d’enregistrement de licence

Une page publique où les clients enregistrent leur code d’achat et l’activent sur leur domaine. La page permet au client de choisir l’origine du code, parmi les marketplaces activées (Manuelle, Envato Market, Gumroad).

Disponible à /{locale}/licenses/register (ou /licenses/register sans préfixe de langue).

URL & Routes

MéthodeURLNom de routeDescription
GET /{locale}/licenses/register front.licenses.register.localized Afficher le formulaire d’enregistrement
POST /{locale}/licenses/register front.licenses.register.localized Traiter l’enregistrement
GET /licenses/register front.licenses.register Variante non localisée

Flux d’enregistrement

  1. Le client visite /licenses/register et remplit sa clé de licence / code d’achat et son domaine.
  2. Le système recherche la clé dans la base de données locale.
  3. Si elle n’est pas trouvée localement, il essaie chaque marketplace activée et configurée (Envato Market, Gumroad) : le code est vérifié auprès de l’API de cette marketplace. S’il est valide, une clé de licence est créée avec cette marketplace (par exemple marketplace = envato).
  4. Si l’utilisateur est authentifié, la LicenseKey est liée à son compte utilisateur (user_id).
  5. Le système appelle LicenseActivationService::activate() avec le domaine fourni.
  6. En cas de succès, le client voit un message de confirmation. En cas d’échec (clé invalide, expirée, activations maximum atteintes), une erreur est affichée.

Champs du formulaire

ChampValidationDescription
license_key Requis, chaîne, max 255 La clé de licence ou le code d’achat Envato
domain Requis, chaîne, max 255 Le domaine où le logiciel est installé (sans http/https)

Vues de thème

Chaque thème fournit sa propre version stylisée du formulaire d’enregistrement à :

Thèmes : default, creative, elegant, minimalist, olive, technology.

Astuce : La page d’enregistrement est liée depuis le menu de navigation front-end via l’entrée front_menu dans addon.json. Le libellé « Enregistrer une licence » apparaît dans le menu d’en-tête.

Portail client (Mes licences)

Les clients authentifiés peuvent consulter toutes leurs licences liées et gérer les activations de domaines. Nécessite la connexion utilisateur (utilise le middleware auth).

URL & Routes

MéthodeURLNom de routeDescription
GET /{locale}/licenses/list front.licenses.my.localized Lister toutes les licences de l’utilisateur
GET /{locale}/licenses/list/{id} front.licenses.my.show.localized Voir les détails de la licence & activations
POST /{locale}/licenses/list/{id}/deactivate front.licenses.my.deactivate.localized Désactiver un domaine

Des variantes non localisées (sans {locale}) sont également disponibles.

Page Mes licences

Affiche une liste/tableau de toutes les licences appartenant à l’utilisateur connecté, montrant :

  • Nom du produit : produit de licence lié
  • Clé de licence : masquée par défaut (ex. XXXX-XXXX-XXXX-ab12), avec un bouton de copie
  • Badge de statut : Active (vert), Expirée (ambre), Suspendue (rouge), Révoquée (sombre)
  • Type de licence : Standard, Étendue, Essai, À vie
  • Activations : nombre / max (ex. « 2 / 3 »)
  • Date d’expiration : ou « Jamais » pour les licences à vie
  • Lien Voir les détails

Page de détail de la licence

Affiche les informations complètes pour une licence unique :

  • Informations sur la clé : clé complète (masquée avec bouton de révélation via JavaScript natif), statut, type, dates d’émission/expiration
  • Domaines actifs tableau : domaine, adresse IP, date d’activation et un bouton Désactiver pour chacun
  • Historique des activations : toutes les activations (actives + désactivées) avec horodatages

Désactivation

Les clients peuvent auto-désactiver les domaines qu’ils n’utilisent plus. La désactivation :

  1. Vérifie que la licence appartient à l’utilisateur authentifié
  2. Appelle LicenseActivationService::deactivateByDomain()
  3. Libère un emplacement d’activation pour utilisation sur un autre domaine
  4. Redirige avec un message de succès

Vues de thème

Menu utilisateur : Le lien « Mes licences » apparaît dans le menu déroulant du compte utilisateur (configuré via user_menu dans addon.json, icône : bi-key).

Génération automatique via la boutique

Lorsque l’add-on Boutique est actif, que la marketplace Boutique est activée et qu’un produit de la boutique possède une fiche sur un produit de licence, les clés de licence sont automatiquement générées lorsqu’une commande est confirmée.

Configuration

  1. Activez la marketplace Boutique dans Licences → Paramètres (activée par défaut).
  2. Créez la fiche du produit de la boutique sur un produit de licence, dans un sens ou dans l’autre :
    • sur le produit de la boutique, cliquez sur Créer / Mettre à jour le produit de licence ; ou
    • dans Licences → Produits, modifiez le produit de licence et choisissez le produit de la boutique dans sa section Boutique (voir Où un produit est vendu).
  3. Vérifiez les SKU : le produit de la boutique et le produit de licence doivent porter le même SKU (voir synchronisation des SKU).

Flux de génération automatique

  1. Un client effectue un achat via la boutique.
  2. Le payment_status de la commande passe à paid, ou son statut passe à processing ou completed (par exemple une commande en paiement à la livraison acceptée).
  3. Le ShopOrderObserver détecte le changement.
  4. Pour chaque article de commande dont le produit de la boutique possède une fiche sur un produit de licence :
    • Une clé de licence est créée par quantité d’article (ex. qté 2 → 2 clés)
    • Sa marketplace est shop
    • Le statut est défini à active
    • marketplace_reference est défini à shop_order:{order_number} (empêche la génération en double)
    • La clé utilise le format UUID
  5. Un e-mail LicenseKeyIssuedNotification est envoyé au client avec :
    • Salutation avec le nom du client
    • Toutes les clés de licence générées
    • Un bouton « Enregistrer une licence » pointant vers /licenses/register
    • Instructions sur la manière d’activer

Prévention des doublons

L’observateur vérifie l’existence de clés avec le même marketplace_reference avant de générer. Si des clés pour shop_order:ORD-12345 existent déjà, l’observateur ignore la génération. Cela empêche les doublons si le statut de paiement est mis à jour plusieurs fois.

Remboursements et annulations

Lorsqu’une commande confirmée est remboursée, annulée, ou que son paiement échoue ou repasse en attente, ses clés actives sont suspendues et le client est notifié. Confirmer de nouveau la commande réactive les mêmes clés.

Modifié en v1.0.13 : le lien entre un produit de la boutique et un produit de licence est désormais sa fiche Boutique. L’ancienne colonne shop_products.license_product_id est supprimée par la mise à jour, après que ses liens ont été copiés dans les fiches.
Prérequis : L’add-on Boutique doit être installé et actif.
Remarque : Les clés sont émises lorsqu’une commande existante change (et non lors de sa création). Une commande créée directement comme payée n’émet pas de clés : son statut doit passer ensuite à payé, en traitement ou terminé.

Désinstallation

Éteindre un add-on sans rien perdre, c’est le désactiver : allez dans Panneau d’administration → Add-ons, trouvez License Management et cliquez sur Désactiver.

  • Ses routes, ses vues, ses entrées de menu d’administration et ses permissions cessent d’être enregistrées, et ses pages publiques ne répondent plus.
  • Ses tables de base de données et toutes les données qu’elles contiennent sont conservées, et ses fichiers restent dans extensions/addons/licenses/. Rien n’est supprimé.
  • Le code d’achat enregistré lors de l’activation est conservé lui aussi : réactiver l’add-on ne le redemande pas.
  • La désactivation est refusée tant qu’un autre add-on actif dépend de celui-ci : désactivez d’abord cet add-on.

Cliquez sur Activer sur la même carte pour le rallumer. Les migrations en attente sont rejouées, les assets republiés, et l’add-on reprend exactement là où il s’était arrêté.

Suppression

La suppression est définitive et détruit les données de l’add-on. Le bouton Supprimer n’apparaît que sur un add-on désactivé : la suppression se fait donc toujours en deux temps :

  1. Désactivez License Management (voir Désinstallation).
  2. Cliquez sur Supprimer sur sa carte et confirmez la demande.

Le panneau d’administration, en une seule passe :

  • exécute le hook de désinstallation de l’add-on, s’il en fournit un, tant que son code est encore sur le disque ;
  • révoque les permissions déclarées dans son addon.json ;
  • annule ses migrations, ce qui supprime ses tables de base de données et toutes les lignes qu’elles contiennent, et purge ses entrées de la table migrations, afin qu’une réinstallation ultérieure reparte de zéro ;
  • supprime ses assets publiés : public/addons/licenses/, public/vendor/licenses/ et storage/app/public/addons/licenses/ ;
  • supprime le dossier de l’add-on extensions/addons/licenses/ ;
  • supprime sa ligne dans la table addons (le code d’achat enregistré disparaît avec elle) et vide le cache de l’application.
Cette action est irréversible. Sauvegardez votre base de données avant de supprimer un add-on dont les données peuvent encore vous servir : le réinstaller plus tard crée des tables vides, pas votre ancien contenu.

La suppression est refusée, avec un message explicatif et avant toute destruction, lorsque l’add-on est encore actif, lorsqu’un autre add-on actif en dépend, ou lorsque l’utilisateur du serveur web (PHP) ne peut pas supprimer extensions/addons/licenses/. Dans ce dernier cas, donnez à cet utilisateur le droit d’écriture sur le dossier et sur son parent, puis réessayez.

Supprimer le dossier en FTP ou en SSH n’est pas équivalent : les tables de l’add-on, ses entrées dans la table migrations et sa ligne addons restent en place, et sa carte reste dans la liste. Utilisez plutôt Supprimer dans le panneau d’administration.

Dépannage

L’API renvoie 503 : « License API is not configured »

Vous n’avez pas défini de clé API. Allez dans Licences → Paramètres et définissez le champ API Key, ou définissez LICENSES_API_KEY dans .env.

L’API renvoie 401 : « Invalid API key »

L’en-tête X-Api-Key ou le paramètre api_key ne correspond pas à la clé configurée. Vérifiez les espaces en début/fin ou les problèmes d’encodage.

L’activation échoue avec « Maximum activations reached »

La clé a atteint sa limite max_activations. Options :

  • Désactivez un domaine inutilisé via POST /deactivate ou depuis le panneau d’administration
  • Augmentez max_activations sur la clé dans le panneau d’administration

La vérification Envato échoue

Vérifiez que :

  • Le jeton API Envato a les permissions View Your Envato Account Username et Verify Purchases
  • Le Author Username correspond exactement à votre profil Envato (sensible à la casse)
  • Le code d’achat est valide et appartient à l’un de vos articles

Les événements webhook sont journalisés comme « Échec »

Causes courantes :

  • Signature invalide : L’en-tête X-Webhook-Signature ne correspond pas. Assurez-vous que les deux côtés utilisent le même secret et calculent HMAC-SHA256 sur le corps brut de la requête.
  • Produit manquant : Le slug product dans les données ne correspond à aucun produit actif. Créez d’abord le produit.
  • Événement invalide : Le champ event doit être l’un de : license.created, license.updated, license.revoked, license.expired.

La page d’enregistrement renvoie « Clé de licence invalide »

La clé n’a pas été trouvée localement et la vérification Envato a également échoué. Vérifiez :

  • Le jeton API Envato et le nom d’utilisateur auteur sont correctement configurés dans Licences → Paramètres
  • Le code d’achat est valide et appartient à l’un de vos articles Envato
  • Si vous utilisez des clés manuelles, assurez-vous que la clé existe dans Licences → Clés de licence

Le domaine local n’est pas contourné

Vérifiez que :

  • Le contournement des domaines locaux est activé dans Licences → Paramètres (ou LICENSES_LOCAL_DOMAIN_BYPASS=true dans .env)
  • Le domaine correspond à l’un des motifs configurés (les motifs utilisent la syntaxe fnmatch())
  • Le domaine n’inclut pas le protocole : utilisez localhost et non http://localhost

L’achat en boutique ne génère pas de clés de licence

Vérifiez que :

  • La marketplace Boutique est activée dans Licences → Paramètres
  • Le produit de la boutique possède une fiche sur un produit de licence (sa section Boutique dans le formulaire produit, ou le bouton Créer / Mettre à jour le produit de licence du produit de la boutique)
  • Le statut de paiement de la commande est bien changé en payé (ou son statut en en traitement / terminé)
  • Vérifiez la colonne marketplace_reference : si des clés avec shop_order:{order_number} existent déjà, l’observateur ignore la génération

« License key does not belong to this product »

La clé est valide, mais la valeur product envoyée par le client ne correspond pas au produit de la clé. Vérifiez que :

  • le SKU du produit est celui déclaré par le addon.json / theme.json du client (clé sku) ;
  • le produit possède une fiche sur la plateforme de vente d’où provient la clé, avec les bons identifiants (voir Où un produit est vendu) ;
  • pour les anciens clients qui n’envoient que le nom du répertoire : le produit porte ce nom comme slug ou comme alias de slug. Lorsque deux gammes de produits partagent un nom de répertoire, donnez l’alias aux deux produits (voir Alias de slug partagés).

Voir Comment l’API reconnaît un produit.

« Créer / Mettre à jour le produit de licence » refuse de s’exécuter sur un produit de la boutique

  • Les SKU diffèrent : le produit de la boutique et son produit de licence portent deux SKU différents. Rendez-les identiques, puis cliquez de nouveau.
  • Le SKU est déjà utilisé : un autre produit de licence possède déjà le SKU du produit de la boutique. Changez-en un, ou fusionnez les deux produits de licence.

La vérification côté client affiche « License Invalid »

Vérifiez que :

  • LICENSE_API_BASE_URL pointe vers le bon serveur (ex. https://your-site.com/api/licenses)
  • LICENSE_API_KEY correspond au LICENSES_API_KEY sur le serveur
  • Le code d’achat est valide et n’a pas été révoqué
  • Le serveur est joignable depuis le client (pas de problèmes de pare-feu/DNS)

Add-on Gestion de Licences v1.0.0 : fait partie de la plateforme CMS Larapen.

© BeDigit. Tous droits réservés.

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

Guides des Modules

avr. 07, 2026