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
- Lors de la publication, activez l'« activation de licence » et conservez le Secret API logiciel (licenseApiSecret) généré ;
- 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) ;
- 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: trueaux 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, etlicenseCodeest 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
expiryTimeet 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à,
unbindQuotaExceededest 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
- 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; - É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 →
activatedans le client pour lier l'appareil et obtenir le jeton →verifyau démarrage ; - Changement d'appareil : dissocier l'ancien appareil via
deactivatedans Mon profil →activatesur le nouvel appareil →verify; - 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
clientOrderIdglobalement unique (ex. horodatage + aléa) ; les demandes répétées n'émettent pas de doublons ; - Cache : les résultats de
verifysont 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.