Referencia del servidor
Webhooks
Copiar página
Lia le informa a tu servidor cuando se paga o se reembolsa un cargo y cuando se paga una recompensa, firmado con tu secreto de webhook. Lo que se envía, cómo verificar la firma y cómo funcionan los reintentos.
#Configurar uno
Dale a la equipo de Lia una dirección https en tu servidor y mantén secreto el sello de la webhooks (whsec_…) que vinieron con tus claves. Lia envía un POST ahí cuando algo sucede en tu app.
Un webhook es un sugerencia, no la verdad: compruébelo con el API antes de actuar sobre uno (para un cargo, GET /charges/:id. Y no'no confíe solo en webhooks; su página también puede decirle a su servidor (ver Vender un artículo).
#¿Qué'se enviaron
POST /lia/webhook
Content-Type: application/json
Lia-Signature: t=1761998400,v1=5f2c8a…
{
"type": "charge.paid",
"app": "your-app",
"at": 1761998400123,
"data": {
"id": "ch_9b1f4c2e7a0d5b8f3e6a1c4d",
"playerId": "p_3f9c0a6d1b2e4f5a6b7c",
"productId": "extra-lives",
"amount": 5,
"status": "paid",
"mode": "live",
"createdAt": 1761998400000,
"deliveredAt": null,
"refundedAt": null
}
}| Campo | Tipo | |
|---|---|---|
type | cadena | Lo que sucedió (abajo). |
app | cadena | Tu app id. |
at | número | Cuándo se envió, en milisegundos desde 1970. |
data | objeto | ¿Qué's sobre. |
#Tipos
| Tipo | Cuándo | data |
|---|---|---|
charge.paid | Una persona pagó en Lia'la nómina, en pruebas o en producción. | El carga, con status: "paid" |
charge.refunded | Reembolsaste una carga. | La tarifa, con status: "refunded" |
reward.paid | Pagaste una recompensa desde tu grupo, en prueba o en vivo. | { key, playerId, amount, reason, mode } |
Verificar data.mode (o el cargo's mode) así que los eventos de prueba nunca otorgan nada real. Pueden agregarse más tipos: ignora los tipos que no conozcas'saber y responder 200.
#Verificación de la firma
Cada webhook tiene un Lia-Signature encabezado, t=<seconds>,v1=<signature>. La firma es HMAC SHA-256, en hexadecimal, de los segundos, un punto, y el cuerpo sin procesar, con clave de tu secreto de webhook completo (incluyendo whsec_):
v1 = hex(HMAC_SHA256(key = "whsec_…", message = t + "." + rawBody))Verifica contra el cuerpo sin procesar exactamente como llegó, antes de analizarlo, y rechaza webhooks con más de unos minutos de antigüedad.
import { createHmac, timingSafeEqual } from "node:crypto";
export function liaWebhook(rawBody, header, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries((header ?? "").split(",").map((part) => part.split("=")));
const t = Number(parts.t);
if (!t || !parts.v1) return null;
if (Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return null;
const expected = Buffer.from(createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex"));
const given = Buffer.from(parts.v1);
if (expected.length !== given.length || !timingSafeEqual(expected, given)) return null;
return JSON.parse(rawBody);
}export async function liaWebhook(request, secret, toleranceSeconds = 300) {
const rawBody = await request.text();
const parts = Object.fromEntries((request.headers.get("Lia-Signature") ?? "").split(",").map((part) => part.split("=")));
const t = Number(parts.t);
if (!t || !parts.v1 || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return null;
const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["verify"]);
const signature = new Uint8Array(parts.v1.match(/../g).map((byte) => parseInt(byte, 16)));
const ok = await crypto.subtle.verify("HMAC", key, signature, new TextEncoder().encode(`${t}.${rawBody}`));
return ok ? JSON.parse(rawBody) : null;
}Manejar webhooks tiene un manejador completo.
#Respuestas y reintentos
- Respuesta con cualquier
2xxestado, rápidamente. Haga trabajo lento después de responder. - Si su servidor no't respuesta
2xx(o puede't ser alcanzado), Lia intenta una vez más inmediatamente. Después de eso, el webhook no'no se envió de nuevo. - Así que los webhooks pueden perderse y pueden llegar dos veces. Haga que su manejador sea seguro para ejecutarse dos veces (clave con el id de cargo o la clave de recompensa), y tenga otro modo de recuperarse, como
Lia.charges()cuando el jugador abre su aplicación.
#Tu secreto
Su secreto de webhook cambia cada vez que se generan nuevamente sus claves. Guárdelo en su servidor, junto con su clave.
Traducido automáticamente. El inglés es la fuente de verdad. Leer en inglés