Actualizado el 12 oct 2026
Webhooks firmados
Envía eventos de tus solicitudes a tus sistemas y verifica la firma HMAC-SHA256 de cada envío.
Un webhook le avisa a otro sistema, como Zapier o tu hoja de producción, cuando algo pasa en una solicitud. Cada envío va firmado con un secreto para que compruebes que viene de Promptusphere. Solo Dueña o dueño y Administración pueden configurarlos.
Agrega un endpoint
- 1. Ve a Ajustes, Webhooks y elige Agregar endpoint.
- 2. Escribe la URL del endpoint. Debe empezar con
https://y ser pública. - 3. Elige los Eventos:
request.created,request.status_changed,request.ready,request.completed,approval.recordedoquote.decided. - 4. Guarda. Te mostramos el secreto de firma una sola vez: elige Copiar secreto, guárdalo en tu sistema y elige Ya lo guardé.
- 5. Elige Enviar evento de prueba para confirmar que llega.
Verifica la firma
Cada envío incluye este encabezado:
Promptusphere-Signature: t=<unix seconds>,v1=<hex>- 1. Separa
t(segundos desde 1970) yv1(la firma en hexadecimal). - 2. Rechaza el evento si la diferencia entre la hora actual y
tes mayor a 300 segundos (5 minutos). Así evitas repeticiones. - 3. Calcula HMAC-SHA256 con tu secreto sobre el texto
t+.+ el cuerpo crudo de la petición, antes de convertirlo de JSON. Expresa el resultado en hexadecimal. - 4. Compara tu resultado con
v1en tiempo constante. Si no coinciden, responde con un error y no proceses el evento.
Este ejemplo en JavaScript usa Web Crypto (crypto.subtle):
// Verifies the Promptusphere-Signature header with Web Crypto.
// Works in Cloudflare Workers, Deno and Node 20+ (in Node 18, use webcrypto from node:crypto).
const TOLERANCE_SECONDS = 300;
const encoder = new TextEncoder();
function toHex(buffer) {
return [...new Uint8Array(buffer)].map((b) => b.toString(16).padStart(2, "0")).join("");
}
function timingSafeEqual(a, b) {
if (a.length !== b.length) return false;
let diff = 0;
for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
return diff === 0;
}
export async function verifyPromptusphere(rawBody, header, secret) {
if (!header) return false;
const parts = {};
for (const piece of header.split(",")) {
const [key, value] = piece.trim().split("=");
if (key && value) parts[key] = value;
}
const t = Number(parts.t);
if (!Number.isInteger(t) || !parts.v1) return false;
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - t) > TOLERANCE_SECONDS) return false;
const key = await crypto.subtle.importKey(
"raw",
encoder.encode(secret),
{ name: "HMAC", hash: "SHA-256" },
false,
["sign"],
);
const mac = await crypto.subtle.sign("HMAC", key, encoder.encode(t + "." + rawBody));
return timingSafeEqual(toHex(mac), parts.v1);
}
// Example: a Cloudflare Worker that receives the webhook.
export default {
async fetch(request, env) {
const rawBody = await request.text(); // raw body, before JSON.parse
const header = request.headers.get("Promptusphere-Signature");
const ok = await verifyPromptusphere(rawBody, header, env.PROMPTUSPHERE_WEBHOOK_SECRET);
if (!ok) return new Response("invalid signature", { status: 400 });
const event = JSON.parse(rawBody);
// event.id, event.type (for example request.ready), event.createdAt, event.data
return new Response("ok");
},
};Entregas y reintentos
- Responde con un código 2xx en menos de 10 segundos. Cualquier otro resultado cuenta como fallo.
- Reintentamos los envíos fallidos varias veces, con esperas cada vez más largas.
- En Ver entregas está el Registro de entregas con las últimas 50, su resultado y sus intentos. Usa Reenviar para mandar una de nuevo.
- Cada envío trae también los encabezados
Promptusphere-EventyPromptusphere-Delivery. Usa eliddel evento para ignorar duplicados.
soporte@promptusphere.com
¿Sigues con dudas?
Escríbenos con el nombre de la solicitud o la pantalla donde estabas y te ayudamos a revisarlo.