Skip to content

Casos de uso

Emitir claves automáticamente desde una tienda

Conecta una tienda o un Merchant-of-Record a Keyright para que un pedido pagado acuñe una clave de licencia y la envíe por correo al comprador automáticamente — con eventos verificados por HMAC, reintentos idempotentes y revocación impulsada por reembolsos.

Objetivo. Un cliente paga en tu tienda (o en un Merchant-of-Record que vende en tu nombre), y se acuña una licencia de Keyright que se le envía por correo sin ningún paso manual — y un reembolso o una cancelación la revoca con la misma automaticidad.

Cuándo usarlo

  • Úsalo si vendes a través de un proceso de pago — tu propia tienda, un proveedor de pagos o un Merchant-of-Record (MoR) que gestiona impuestos y facturación — y quieres que la entrega de pedidos no requiera intervención.
  • Úsalo si quieres que los reembolsos y las cancelaciones corten el acceso sin que alguien tenga que acordarse de revocar.
  • No lo uses si emites claves a mano para un puñado de cuentas empresariales (usa simplemente Licenses → Issue license o POST /admin/licenses), o si tu sistema de facturación ya llama por sí mismo a la API de administración — el webhook es una comodidad, no la única vía.

Esto es principalmente una comodidad de Cloud — el servicio alojado ya es accesible desde la internet pública, así que una tienda puede hacerle POST directamente. También funciona autoalojado, siempre que la tienda pueda alcanzar tu instancia (una URL pública o un túnel al que el proveedor pueda llegar); todo lo que sigue es idéntico salvo la URL base.

Tienda / MoRel comprador pagaproducto + varianteHMACPOST /webhooks/fulfill/{slug}1. verificar X-Keyright-Signature2. asignar → producto + edición3. acuñar licencia (idempotentepor orderRef)4. enviar la clave por correoEl comprador recibe la clavela pega en tu aplicaciónreembolso / cancelación→ revoca la misma licenciaEl tenant se toma de la ruta y se fuerza en el evento, así que una firma válida para un tenant nunca puede acuñar en otro.Un «paid» duplicado para el mismo orderRef devuelve la licencia existente en lugar de emitir una segunda.Keyright nunca procesa el pago — reacciona al evento normalizado que envía tu tienda (o un adaptador ligero).
Un pedido pagado se convierte en una clave de licencia firmada y enviada por correo; un reembolso la revoca — todo desde un único webhook verificado por HMAC.

Qué haces tú (lado del proveedor)

1. Obtén tu URL de webhook y tu secreto

Cada tenant tiene un webhook de entrega por tenant en POST /webhooks/fulfill/{slug} (donde {slug} es tu tenant) y un secreto que se usa para firmar los eventos con HMAC. El tenant se toma de la ruta y se fuerza en el evento, de modo que una firma válida para un tenant nunca puede acuñar una licencia en otro.

Encuentra ambos en la configuración de integración/desarrolladores del panel, o a través de la API: GET /admin/account devuelve un bloque integration con la URL base, la clave pública de firma y la URL del webhook. Rota el secreto en cualquier momento (rol de propietario):

curl -X POST $BASE/admin/webhook-secret/rotate -H "X-Admin-Token: $TOKEN"
# -> { "webhookSecret": "…", "webhookUrl": "https://keyright.delta1labs.com/webhooks/fulfill/acme" }

2. Apunta tu tienda hacia él

En tu tienda / proveedor de pagos / MoR, añade un webhook que se dispare en el ciclo de vida del pedido y configura:

  • URL — tu /webhooks/fulfill/{slug}.
  • Secreto de firma — el webhookSecret de arriba. El proveedor firma con HMAC el cuerpo bruto de la petición y lo envía en la cabecera X-Keyright-Signature; Keyright lo verifica con tu secreto y rechaza todo lo que no coincida (401).

La mayoría de las tiendas emiten su propia forma de evento. Keyright espera un evento normalizado, así que si la carga útil de tu proveedor difiere, coloca delante un adaptador ligero (una pequeña función que traduce el webhook del proveedor al cuerpo normalizado, lo firma y lo reenvía). El cuerpo normalizado:

{
  "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"
}
  • type determina la acción: un evento paid (paid / order.paid / issue) acuña una licencia; un evento refund / cancel / revoke la revoca.
  • product y tier son la forma de asignar el producto/variante de la tienda a un producto + edición de Keyright. Tu tienda vende un SKU; tú decides a qué slug de product de Keyright y a qué tier (edición) corresponde ese SKU, y pones esos campos en el evento (directamente, o en la tabla de asignación de tu adaptador). Los puestos, los derechos y cualquier política de cobertura de la edición se aplican automáticamente al emitir, exactamente igual que en una licencia emitida a mano — así que una clave Pro entregada por una tienda es indistinguible de una emitida en el panel.
  • seats / expiryUtc anulan los valores predeterminados de la edición cuando el SKU lo necesita (p. ej. un paquete de 5 puestos, o un plazo anual).
  • orderRef es el ancla de idempotencia (siguiente sección) — envía siempre el id de pedido de tu tienda.
  • email es adonde se envía la clave.

Un campo tenant en el cuerpo se ignora en la ruta por tenant — el slug de la URL siempre gana.

3. Qué recibe el cliente

Ante un evento paid, Keyright acuña la licencia y envía la clave por correo a email (la instancia necesita SMTP configurado para que el correo salga). El comprador pega esa clave en tu aplicación y la activa como cualquier otra licencia — consulta Primeros pasos. Nada en la activación, los puestos o los derechos cambia por el hecho de que la clave venga de una tienda.

Idempotencia y reintentos

Las tiendas reintentan los webhooks — ante un tiempo de espera agotado, un 5xx o un fallo puntual del proveedor recibirás el mismo evento más de una vez. Keyright hace que paid sea idempotente por orderRef: la primera entrega acuña la licencia, y cada entrega posterior con el mismo orderRef devuelve la licencia existente en lugar de emitir una segunda clave. Por eso orderRef debe ser estable (el id de pedido de tu tienda, no un id por intento). El endpoint responde 200 para cada resultado gestionado — issued, already exists, revoked o ignored — de modo que una tienda bien comportada ve éxito y deja de reintentar.

Los eventos de reembolso/cancelación revocan la licencia que ese pedido acuñó; la aplicación del cliente baja a Free en su siguiente renovación de lease (consulta Revocar, renovar y gestionar el vencimiento). Un reembolso de un pedido que nunca se entregó no hace nada (ignored, igualmente 200).

En tu código

No hay trabajo del lado del SDK para la entrega de pedidos — es un flujo servidor a servidor entre tu tienda y Keyright, y la aplicación del cliente solo ve una clave de licencia ordinaria. El único código que podrías escribir es el adaptador opcional que normaliza el webhook de tu proveedor. Esbozo:

// Minimal adapter: translate a provider event into Keyright's normalized, HMAC-signed body.
var evt = new {
    type     = providerEvent.IsPaid ? "paid" : "refund",
    licensee = providerEvent.CustomerName,
    product  = MapToKeyrightProduct(providerEvent.Sku),   // your SKU → Keyright product slug
    tier     = MapToKeyrightTier(providerEvent.Sku),      // your SKU → edition
    seats    = providerEvent.Quantity,
    orderRef = providerEvent.OrderId,                     // the idempotency anchor
    email    = providerEvent.CustomerEmail,
};
var body = JsonSerializer.SerializeToUtf8Bytes(evt);
var sig  = Convert.ToBase64String(new HMACSHA256(secretBytes).ComputeHash(body));   // over the RAW bytes
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 tu proveedor puede enviar directamente un cuerpo JSON personalizado y un esquema de firma personalizado (algunos pueden), quizá no necesites ningún adaptador — apúntalo directamente al webhook con la forma normalizada de arriba.

Cloud frente a autoalojado

  • La accesibilidad es la única diferencia real: Cloud es público, así que una tienda llega a https://keyright.delta1labs.com/webhooks/fulfill/{slug} sin más; una instancia autoalojada debe ser accesible para la tienda en una URL a la que pueda hacer POST.
  • La ruta heredada de un solo tenant. Una instancia autoalojada de un solo tenant puede usar en su lugar la ruta global del despliegue POST /webhooks/fulfill con un KEYRIGHT_WEBHOOK_SECRET. Prefiere la ruta por tenant /webhooks/fulfill/{slug} siempre que la instancia tenga más de un tenant.
  • $BASE / $TOKEN / SMTP siguen la división habitual; el paso de la clave enviada por correo necesita correo configurado en la instancia que acuñe la licencia.

Verificar

  1. Rota el secreto del webhook y anótalo; asigna un SKU de la tienda a product=acme-app, tier=pro.
  2. Envía un evento paid de prueba con un email real y un orderRef nuevo, firmado con el secreto. Espera 200, una licencia nueva en Licenses y la clave en la bandeja de entrada.
  3. Idempotencia: reenvía exactamente el mismo evento. Espera 200 y ninguna segunda licencia — vuelve la misma clave.
  4. Firma incorrecta: envía el mismo cuerpo con una firma errónea. Espera 401 y ninguna licencia.
  5. Reembolso: envía un evento refund para ese orderRef. La licencia pasa a revocada; la aplicación del cliente baja a Free en la siguiente renovación.

Véase también