Documentation API ouverte des licences

v1.0

Documentation API ouverte des licences

Ce document s'adresse aux développeurs qui souhaitent intégrer le flux complet « paiement → émission → activation → vérification » dans leur propre logiciel (logiciel client / produits en promotion seule). Chaque API est décrite avec son moment d'appel, ses paramètres de requête, ses champs de réponse et ses codes d'erreur.

1. Concepts de base

Concept Champ / terme Description
Secret API logiciel licenseApiSecret Généré automatiquement lorsque le produit active « activation de licence ». Consultable dans le formulaire d'édition du produit du Centre développeur. Votre serveur logiciel l'utilise pour calculer la signature HMAC, la plateforme l'utilise pour la vérifier. À conserver uniquement côté serveur, ne jamais l'intégrer au client.
Code de licence licenseCode Code unique généré par la plateforme. L'utilisateur l'utilise pour activer votre logiciel.
Code machine machineCode Identifiant d'appareil généré par le logiciel client (unique par ordinateur ; hacher une empreinte machine stable, 8 caractères minimum).
Jeton d'activation activationToken Délivré par la plateforme lors de l'activation / de l'émission. Le logiciel le conserve et le renvoie à chaque vérification au démarrage.
Identifiant de commande clientOrderId Identifiant de la commande de paiement intégré (généré par le client ou le serveur). La plateforme déduplique via « produit + identifiant de commande » pour éviter les doubles débits et double émission.

2. Préparation

  1. Lors de la publication, activez l'« activation de licence » et conservez le Secret API logiciel (licenseApiSecret) généré ;
  2. Dans le formulaire de publication, configurez la liste des éditions (ex. BASIC/PRO/ULTIMATE) et la stratégie de mise à niveau (SAME_CODE = mise à niveau avec le même code / NEW_CODE = émettre un nouveau code) ;
  3. Conservez le secret sur votre serveur logiciel ; le client ne garde que le code de licence et le jeton d'activation.

3. Vue d'ensemble des API

Préfixe : https://www.powersoftware.app/frontApi (remplacez par votre domaine de déploiement en local / test).

API Moment d'appel Authentification Signature
POST /license/software/generate Juste après un paiement intégré réussi Aucune (vérification de signature) Requise
POST /license/software/upgrade Juste après un paiement de renouvellement / mise à niveau réussi Aucune (vérification de signature) Requise
POST /license/activate Première activation / changement d'appareil Aucune Non requise
POST /license/verify À chaque démarrage du logiciel Aucune Non requise
POST /license/deactivate L'utilisateur dissocie l'ancien appareil (Mon profil) Connexion Non requise

4. Règles de signature (requises pour generate / upgrade)

Chaîne à signer : concaténez les champs suivants dans cet ordre exact avec des retours à la ligne (\n) (champs facultatifs absents avec des valeurs vides : edition chaîne vide, expiryDays = 0) :

productId \n machineCode \n edition \n expiryDays \n clientOrderId \n licenseCode \n timestamp

Signature : HMAC-SHA256(Secret API logiciel licenseApiSecret, chaîne à signer), encodée en Base64URL, à placer dans le champ signature.

Protection contre la relecture : timestamp est un horodatage en millisecondes. La plateforme exige un écart maximal de 5 minutes avec l'heure du serveur, sinon signatureInvalid est renvoyé.

Exemple Node.js :

const crypto = require("crypto");
const payload = [productId, machineCode, edition, expiryDays, clientOrderId, licenseCode, timestamp].join("\n");
const signature = crypto.createHmac("sha256", API_SECRET).update(payload).digest("base64url");

Exemple Python :

import hashlib, hmac, base64
payload = "\n".join([str(productId), machineCode, edition, str(expiryDays), clientOrderId, licenseCode, str(timestamp)])
signature = base64.urlsafe_b64encode(hmac.new(API_SECRET.encode(), payload.encode(), hashlib.sha256).digest()).decode().rstrip("=")

(Le Base64URL est le Base64 standard avec + remplacé par -, / remplacé par _, et le remplissage = final supprimé.)

5. Détail des API

5.1 Générer un code de licence (appeler après paiement intégré)

Moment d'appel : juste après qu'un paiement intégré a réussi, votre serveur appelle l'API une fois et conserve le code de licence et le jeton d'activation retournés. La même commande ne doit être envoyée qu'une seule fois ; les appels répétés sont idempotents et n'émettent pas de second code.

POST /license/software/generate

Paramètres de requête (corps JSON) :

Paramètre Type Obligatoire Source Description
productId number Oui Intégré / config serveur Identifiant du produit, identique au produit publié sur la plateforme
machineCode string Oui Généré par le client Code machine de l'appareil actuel, 8 caractères minimum
edition string Non Choisi par le client au paiement Identifiant d'édition ; doit être dans la liste des éditions ; par défaut la première édition du produit
expiryDays number Non Choisi par le client au paiement Durée de validité en jours, 0 = permanent ; plage 0-3650
clientOrderId string Oui Généré par le client / serveur Identifiant de commande du paiement intégré, 1-64 caractères ; clé d'idempotence
timestamp number Oui Généré par le serveur Horodatage en millisecondes
signature string Oui Calculé par le serveur Signature HMAC, 10 caractères minimum

Champs de réponse de content :

Champ Type Description
licenseId number Identifiant de l'enregistrement de licence
licenseCode string Le code de licence (à écrire dans vos données de licence)
productId number Identifiant du produit
edition string Identifiant d'édition
machineId number Identifiant de l'enregistrement de machine liée
activatedAt string Heure d'activation (ISO8601)
expiryTime string/null Heure d'expiration (ISO8601), null = permanent
maxMachines number Nombre maximal de machines liables
activationToken string Jeton d'activation ; à conserver pour la vérification au démarrage

Exemple de réponse :

{
  "code": "SUCCESS",
  "requestId": "xxx",
  "success": true,
  "content": {
    "licenseId": 1001,
    "licenseCode": "AB12-CD34-EF56-GH78",
    "productId": 88,
    "edition": "PRO",
    "machineId": 2001,
    "activatedAt": "2026-08-05T10:00:00.000Z",
    "expiryTime": "2027-08-05T10:00:00.000Z",
    "maxMachines": 1,
    "activationToken": "eyJhbGciOiJIUzI1NiJ9..."
  }
}

Codes d'erreur de cette API : productIdRequired, machineCodeInvalid, orderIdRequired, productNotFound, productNotEnabled, apiSecretMissing, signatureInvalid, orderAlreadyUsed.

5.2 Mettre à niveau / renouveler (appeler après paiement)

Moment d'appel : après qu'un paiement de renouvellement ou de mise à niveau a réussi. La même commande ne doit être envoyée qu'une seule fois.

POST /license/software/upgrade

Paramètres de requête (corps JSON) :

Paramètre Type Obligatoire Source Description
productId number Oui Intégré / config serveur Identifiant du produit
licenseCode string Oui Stocké dans le logiciel Code de licence actuel, 10 caractères minimum
machineCode string Non Généré par le client Code machine actuel ; à transmettre pour la migration des liaisons (NEW_CODE) ou une liaison supplémentaire
edition string Oui Choisi par le client au paiement Identifiant d'édition cible
expiryDays number Non Choisi par le client au paiement Durée de validité supplémentaire en jours, 0 = permanent ; plage 0-3650
clientOrderId string Oui Généré par le client / serveur Identifiant de commande de cet achat ; clé d'idempotence
timestamp number Oui Généré par le serveur Horodatage en millisecondes
signature string Oui Calculé par le serveur Signature HMAC

Stratégie de traitement (déterminée par la configuration du produit) :

  • SAME_CODE (mise à niveau avec le même code) : le code de licence ne change pas, les liaisons machine restent valides et la validité est prolongée (une licence permanente reste permanente). La réponse ajoute upgraded: true aux champs du 5.1 ;
  • NEW_CODE (émettre un nouveau code) : l'ancien code est révoqué, un nouveau code est émis et les liaisons machine sont migrées. La réponse renvoie en plus oldLicenseId, et licenseCode est le nouveau code.

Champs de réponse de content : identiques au 5.1, plus upgraded: true ; en NEW_CODE, oldLicenseId est aussi renvoyé (identifiant de l'ancien enregistrement ; l'ancien code a été révoqué).

Codes d'erreur de cette API : productIdRequired, licenseCodeRequired, orderIdRequired, productNotFound, productNotEnabled, apiSecretMissing, signatureInvalid, codeNotFound, revoked, orderAlreadyUsed, editionRequired.

5.3 Activer une licence (première activation / nouvel appareil)

Moment d'appel : après que l'utilisateur a obtenu un code de licence (émission libre, émission par l'administration, etc.) et le saisit sur la page d'activation du logiciel client ; appeler sur le nouvel appareil lors d'un changement d'appareil.

POST /license/activate

Paramètres de requête (corps JSON) :

Paramètre Type Obligatoire Source Description
licenseCode string Oui Saisie utilisateur Code de licence, 10 caractères minimum
machineCode string Oui Généré par le client Code machine de l'appareil actuel, 8 caractères minimum

Champs de réponse de content : identiques au 5.1 (licenseId, licenseCode, productId, edition, machineId, activatedAt, expiryTime, maxMachines, activationToken).

Remarques :

  • Un code de licence peut être lié à plusieurs machines, dans la limite de maxMachines (par défaut la configuration du produit) ;
  • Activer à nouveau la même machine réutilise la liaison existante et réémet un jeton d'activation (idempotent) ;
  • Les activations en échec sont limitées par IP + code de licence ; trop d'échecs renvoient tooManyAttempts.

Codes d'erreur de cette API : codeNotFound, revoked, expired, machineLimit, tooManyAttempts.

5.4 Vérifier une licence (à chaque démarrage)

Moment d'appel : à chaque démarrage du logiciel (ou avant de déverrouiller des fonctions). Le logiciel doit conserver le jeton activationToken renvoyé par 5.1 / 5.2 / 5.3.

POST /license/verify

Paramètres de requête (corps JSON) :

Paramètre Type Obligatoire Source Description
licenseCode string Oui Stocké dans le logiciel Code de licence, 10 caractères minimum
machineCode string Oui Généré par le client Code machine de l'appareil actuel, 8 caractères minimum
activationToken string Oui Émis par la plateforme, stocké par le logiciel Jeton d'activation, 20 caractères minimum

Champs de réponse de content :

Champ Type Description
valid boolean Toujours true (les échecs passent par les codes d'erreur)
licenseId number Identifiant de l'enregistrement de licence
productId number Identifiant du produit
edition string Identifiant d'édition actuel
expiryTime string/null Heure d'expiration (ISO8601), null = permanent

Remarques :

  • Les résultats de vérification sont mis en cache environ 60 secondes ; les opérations d'écriture (révocation, dissociation, mise à niveau) invalident immédiatement le cache, aucun délai à craindre ;
  • Le logiciel doit vérifier expiryTime et cesser de déverrouiller les fonctions après expiration.

Codes d'erreur de cette API : tokenInvalid, machineNotActivated, invalidOrRevoked, expired, tooManyAttempts.

5.5 Dissocier un appareil (avant changement d'appareil, connexion requise)

Moment d'appel : l'utilisateur dissocie l'ancien appareil dans « Mon profil → Mes licences », puis active sur le nouvel appareil via 5.3.

POST /license/deactivate

Paramètres de requête (corps JSON) :

Paramètre Type Obligatoire Source Description
licenseCode string Oui Liste des licences de l'utilisateur Code de licence, 10 caractères minimum
machineCode string Oui Liste des licences de l'utilisateur Le code machine à dissocier, 8 caractères minimum

Champs de réponse de content : true.

Remarques :

  • Seul le propriétaire de la licence (l'acheteur ou l'utilisateur ayant enregistré le code machine lié) peut effectuer cette opération ;
  • Quota de dissociation : par défaut, la même licence ne peut être dissociée qu'une fois en 30 jours (configurable dans la console d'administration) ; au-delà, unbindQuotaExceeded est renvoyé.

Codes d'erreur de cette API : noPermission, machineNotBound, unbindQuotaExceeded.

6. Codes d'erreur

Les erreurs métier utilisent une réponse unifiée (tip contient un message lisible) :

{
  "code": "BUSINESS_WARNING",
  "requestId": "xxx",
  "success": false,
  "errorMessage": "LICENSE_GENERATE_FAILED",
  "tip": "Signature verification failed"
}

Les échecs de validation des paramètres renvoient code: "PARAM_VALIDATE_FAILED" et le message du champ concerné dans tip.

Code d'erreur Signification
productNotEnabled Le produit n'a pas activé l'activation de licence
apiSecretMissing Le produit n'a aucun Secret API logiciel (licenseApiSecret) configuré
signatureInvalid Échec de vérification de la signature (secret incorrect, ordre de la chaîne incorrect ou horodatage hors fenêtre)
machineCodeInvalid Code machine invalide (moins de 8 caractères)
orderAlreadyUsed Cette commande a déjà généré un code de licence (conflit d'idempotence : rejouée avec un autre code machine)
codeNotFound Code de licence introuvable
revoked Code de licence révoqué ou inutilisable
expired Code de licence expiré
invalidOrRevoked Licence invalide ou révoquée lors de la vérification
machineNotActivated Cette machine n'est pas activée
tokenInvalid Jeton d'activation invalide
machineLimit Le nombre maximal de machines liées est atteint
machineNotBound Cette machine n'est pas liée
noPermission Aucune permission sur cette licence
unbindQuotaExceeded La licence ne peut être dissociée qu'une fois en 30 jours ; réessayez plus tard
tooManyAttempts Trop de tentatives ; réessayez plus tard
productNotFound Produit introuvable
editionRequired Veuillez choisir l'édition cible

7. Flux typiques

  1. Boucle de paiement intégré : paiement réussi → software/generate (renvoie le code de licence + le jeton d'activation) → le logiciel les conserve → verify à chaque démarrage → déverrouiller les fonctions ; renouvellement / mise à niveau → software/upgrade ;
  2. Émission libre / par l'administration : un code de licence est généré dans le Centre développeur ou la console d'administration → l'utilisateur reçoit le code → activate dans le client pour lier l'appareil et obtenir le jeton → verify au démarrage ;
  3. Changement d'appareil : dissocier l'ancien appareil via deactivate dans Mon profil → activate sur le nouvel appareil → verify ;
  4. Différence de stratégie de mise à niveau : SAME_CODE conserve le même code ; NEW_CODE émet un nouveau code (l'ancien est révoqué, les liaisons machine sont migrées automatiquement).

8. Remarques

  • Secret côté serveur uniquement : la signature ne doit être calculée que sur votre serveur logiciel ; si le client obtient le secret, le système de licence est compromis ;
  • Stabilité du code machine : utilisez une empreinte machine stable et hachez-la ; si le code machine change après réinstallation du système, dissociez d'abord, puis réactivez ;
  • Idempotence : rendez clientOrderId globalement unique (ex. horodatage + aléa) ; les demandes répétées n'émettent pas de doublons ;
  • Cache : les résultats de verify sont mis en cache environ 60 secondes et invalidés immédiatement par les opérations d'écriture ;
  • Limitation de débit : les activations / vérifications en échec sont limitées ; le client doit afficher des messages d'erreur appropriés et espacer les tentatives ;
  • Fiez-vous à la réponse de la plateforme : validité, édition et limites de machines sont déterminées par la plateforme ; ne les assouplissez pas côté logiciel.