Cas d'usage
Émettre automatiquement des clés depuis une boutique
Connectez une boutique ou un Merchant-of-Record à Keyright pour qu'une commande payée génère une clé de licence et l'envoie automatiquement par e-mail à l'acheteur — avec des événements vérifiés par HMAC, des réessais idempotents et une révocation déclenchée par le remboursement.
Objectif. Un client paie sur votre boutique (ou chez un Merchant-of-Record qui vend pour votre compte), et une licence Keyright est générée et lui est envoyée par e-mail sans aucune étape manuelle — et un remboursement ou une annulation la révoque tout aussi automatiquement.
Quand l’utiliser
- Utilisez ceci si vous vendez via un parcours de paiement — votre propre boutique, un prestataire de paiement ou un Merchant-of-Record (MoR) qui gère la fiscalité et la facturation — et que vous voulez une exécution des commandes sans intervention.
- Utilisez ceci si vous voulez que les remboursements et annulations coupent l’accès sans que quelqu’un ait à penser à révoquer.
- Pas ceci si vous émettez des clés à la main pour une poignée de comptes entreprise (utilisez simplement Licenses → Issue license ou
POST /admin/licenses), ou si votre système de facturation appelle déjà lui-même l’API d’administration — le webhook est une commodité, pas le seul chemin.
C’est avant tout une commodité Cloud — le service hébergé est déjà joignable depuis l’Internet public, donc une boutique peut lui envoyer un POST directement. Cela fonctionne aussi en auto-hébergé, tant que votre instance est joignable par la boutique (une URL publique ou un tunnel que le prestataire peut atteindre) ; tout ce qui suit est identique, à l’URL de base près.
Ce que vous faites (côté éditeur)
1. Récupérer votre URL de webhook et votre secret
Chaque tenant dispose d’un webhook d’exécution des commandes par tenant à POST /webhooks/fulfill/{slug} (où {slug} est votre tenant) et d’un secret utilisé pour signer les événements en HMAC. Le tenant est pris dans la route et imposé à l’événement, de sorte qu’une signature valide pour un tenant ne peut jamais générer une licence dans un autre.
Trouvez les deux dans les paramètres d’intégration/développeur du tableau de bord, ou via l’API : GET /admin/account renvoie un bloc integration avec l’URL de base, la clé publique de signature et l’URL du webhook. Faites tourner le secret à tout moment (rôle owner) :
curl -X POST $BASE/admin/webhook-secret/rotate -H "X-Admin-Token: $TOKEN"
# -> { "webhookSecret": "…", "webhookUrl": "https://keyright.delta1labs.com/webhooks/fulfill/acme" }
2. Y faire pointer votre boutique
Dans votre boutique / prestataire de paiement / MoR, ajoutez un webhook qui se déclenche sur le cycle de vie de la commande et définissez :
- URL — votre
/webhooks/fulfill/{slug}. - Secret de signature — le
webhookSecretci-dessus. Le prestataire signe en HMAC le corps brut de la requête et l’envoie dans l’en-têteX-Keyright-Signature; Keyright le vérifie avec votre secret et rejette tout ce qui ne correspond pas (401).
La plupart des boutiques émettent leur propre forme d’événement. Keyright attend un événement normalisé ; si la charge utile de votre prestataire diffère, placez un adaptateur léger en amont (une petite fonction qui traduit le webhook du prestataire en corps normalisé, le signe et le transmet). Le corps normalisé :
{
"type": "paid",
"licensee": "Acme Inc.",
"product": "acme-app",
"tier": "pro",
"seats": 3,
"expiryUtc": "2027-10-12T00:00:00Z",
"orderRef": "order_8421",
"email": "buyer@acme.com"
}
typepilote l’action : un événement paid (paid/order.paid/issue) génère une licence ; un événement refund / cancel / revoke la révoque.productettiersont la façon dont vous faites correspondre le produit/la variante de la boutique à un produit + une édition Keyright. Votre boutique vend un SKU ; vous décidez à quel slugproductKeyright et à queltier(édition) ce SKU correspond, et vous définissez ces champs dans l’événement (directement, ou dans la table de correspondance de votre adaptateur). Les sièges de l’édition, ses droits et toute politique de couverture sont appliqués automatiquement à l’émission, exactement comme pour une licence émise à la main — une clé Pro issue d’une boutique est donc indiscernable d’une clé émise dans le tableau de bord.seats/expiryUtcsurchargent les valeurs par défaut de l’édition quand le SKU l’exige (p. ex. un pack de 5 sièges, ou une durée annuelle).orderRefest l’ancre d’idempotence (section suivante) — envoyez toujours l’identifiant de commande de votre boutique.emailest l’adresse à laquelle la clé est envoyée.
Un champ tenant dans le corps est ignoré sur la route par tenant — le slug de l’URL l’emporte toujours.
3. Ce que reçoit le client
Sur un événement paid, Keyright génère la licence et envoie la clé par e-mail à email (l’instance doit avoir un SMTP configuré pour que le courrier parte). L’acheteur colle cette clé dans votre application et l’active comme n’importe quelle autre licence — voir Premiers pas. Rien ne diffère dans l’activation, les sièges ou les droits parce que la clé provient d’une boutique.
Idempotence et réessais
Les boutiques réessaient les webhooks — sur un délai d’attente dépassé, un 5xx ou un incident chez le prestataire, vous recevrez le même événement plus d’une fois. Keyright rend paid idempotent par orderRef : la première livraison génère la licence, et chaque livraison ultérieure avec le même orderRef renvoie la licence existante au lieu d’émettre une seconde clé. C’est pourquoi orderRef doit être stable (l’identifiant de commande de votre boutique, pas un identifiant par tentative). L’endpoint répond 200 pour chaque issue traitée — émise, existe déjà, révoquée ou ignorée — de sorte qu’une boutique bien élevée voit un succès et cesse de réessayer.
Les événements de remboursement/annulation révoquent la licence que cette commande a générée ; l’application du client retombe en Free à son prochain rafraîchissement de lease (voir Révoquer, renouveler et gérer l’expiration). Un remboursement pour une commande jamais exécutée est sans effet (ignorée, toujours 200).
Dans votre code
Il n’y a aucun travail SDK côté application pour l’exécution des commandes — c’est un flux de serveur à serveur entre votre boutique et Keyright, et l’application du client ne voit jamais qu’une clé de licence ordinaire. Le seul code que vous pourriez écrire est l’adaptateur facultatif qui normalise le webhook de votre prestataire. Esquisse :
// Adaptateur minimal : traduire un événement du prestataire en corps normalisé et signé HMAC de Keyright.
var evt = new {
type = providerEvent.IsPaid ? "paid" : "refund",
licensee = providerEvent.CustomerName,
product = MapToKeyrightProduct(providerEvent.Sku), // votre SKU → slug de produit Keyright
tier = MapToKeyrightTier(providerEvent.Sku), // votre SKU → édition
seats = providerEvent.Quantity,
orderRef = providerEvent.OrderId, // l'ancre d'idempotence
email = providerEvent.CustomerEmail,
};
var body = JsonSerializer.SerializeToUtf8Bytes(evt);
var sig = Convert.ToBase64String(new HMACSHA256(secretBytes).ComputeHash(body)); // sur les octets BRUTS
using var http = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Post, "https://keyright.delta1labs.com/webhooks/fulfill/acme")
{ Content = new ByteArrayContent(body) };
req.Content.Headers.ContentType = new("application/json");
req.Headers.Add("X-Keyright-Signature", sig);
await http.SendAsync(req);
Si votre prestataire peut envoyer directement un corps JSON personnalisé et un schéma de signature personnalisé (certains le peuvent), vous n’aurez peut-être pas besoin d’adaptateur du tout — faites-le pointer directement sur le webhook avec la forme normalisée ci-dessus.
Cloud ou auto-hébergé
- La joignabilité est la seule vraie différence : le Cloud est public, donc une boutique atteint
https://keyright.delta1labs.com/webhooks/fulfill/{slug}sans rien faire ; une instance auto-hébergée doit être joignable par la boutique à une URL vers laquelle elle peut envoyer un POST. - La route historique mono-tenant. Une instance auto-hébergée mono-tenant peut à la place utiliser la route globale du déploiement
POST /webhooks/fulfillavec unKEYRIGHT_WEBHOOK_SECRET. Préférez la route par tenant/webhooks/fulfill/{slug}dès que l’instance a plus d’un tenant. $BASE/$TOKEN/ SMTP suivent la répartition habituelle ; l’étape d’envoi de la clé par e-mail exige que le courrier soit configuré sur l’instance qui génère la licence, quelle qu’elle soit.
Vérifier
- Faites tourner le secret du webhook et notez-le ; faites correspondre un SKU de boutique à
product=acme-app,tier=pro. - Envoyez un événement paid de test avec un
emailréel et unorderRefinédit, signé avec le secret. Attendez-vous à200, une nouvelle licence dans Licenses, et la clé dans la boîte de réception. - Idempotence : renvoyez exactement le même événement. Attendez-vous à
200et à aucune seconde licence — la même clé revient. - Mauvaise signature : envoyez le même corps avec une signature erronée. Attendez-vous à
401et aucune licence. - Remboursement : envoyez un événement refund pour cet
orderRef. La licence passe à révoquée ; l’application du client retombe en Free au prochain rafraîchissement.
Voir aussi
- Premiers pas — la configuration côté éditeur et ce que l’acheteur fait de la clé.
- Révoquer, renouveler et gérer l’expiration — ce qu’une révocation déclenchée par un remboursement fait à une application en cours d’exécution.
- Conditionner des fonctionnalités et des éditions — les droits que porte une édition émise par une boutique.
- Référence de l’API HTTP — les endpoints de webhook et d’administration au complet.