Pular para o conteúdo

Webhooks (respostas)

Em vez de deixar um processo esperando no ask(), você pode criar o grupo de perguntas com um callback_url. Quando houver resposta (ou o prazo acabar), o notific.me envia a resposta assinada para essa URL. Essas chamadas de saída são os webhooks. (As chamadas que outros sistemas enviam para o notific.me são os hooks.)

const handle = await notific.createAsk({
title: "Approve refund #881?",
questions: [{ id: "ok", type: "yesno", text: "Approve?" }],
callbackUrl: "https://crm.example.com/hooks/notificme",
});
// handle.id, handle.status === "open"

Um POST no seu callback_url com a resposta no corpo JSON e estes cabeçalhos:

Notificme-Signature: t=<unix>,kid=<key id>,sig=<base64url(Ed25519(t + "." + body))>
Notificme-Webhook-Id: <id> (o mesmo em toda nova tentativa: use para deduplicar)
Notificme-Topic: reply
Notificme-Attempt: 1
  • A resposta e o webhook são gravados na mesma transação (outbox transacional), então a decisão nunca se perde.
  • Qualquer 2xx conta como entregue. Erros e timeouts (15 s) são repetidos com backoff exponencial por até 24 horas.
  • Webhooks no app.notific.me lista cada entrega com status, tentativas e último erro, e permite reenviar.

O servidor assina com Ed25519. As chaves públicas ficam em <api>/.well-known/notificme-keys.json (JWKS). Assinaturas com mais de 5 minutos de diferença do seu relógio são rejeitadas.

import express from "express";
import { NotificMe, expressWebhook, expressWebhookOf } from "@notificme/sdk";
const notific = new NotificMe();
const app = express();
// Put the middleware before any JSON parser (it reads the raw body).
app.post("/hooks/notificme", expressWebhook({ key: notific.keysUrl }), (req, res) => {
const webhook = expressWebhookOf(req)!; // verified
console.log(webhook.reply?.status, webhook.reply?.asText);
res.sendStatus(204);
});

Todo helper responde 401 {"error":{"code":"invalid_signature"}} quando a assinatura é inválida, e o seu handler nunca vê essa requisição.

import { receiveWebhook, verifyWebhook } from "@notificme/sdk";
// Throws WebhookVerificationError (error.reason says why).
await verifyWebhook(rawBody, headers["notificme-signature"], keys);
// Verify and parse: headers, JSON payload and, for the "reply" topic, a typed result.
const webhook = await receiveWebhook(rawBody, headers, keys, { questions });
webhook.reply?.answers.ok;

A chave pode ser a URL das chaves (baixada e guardada em cache), uma string base64url, os bytes, um JWK ou um JWKS. WebhookVerificationError.reason é missing_header, malformed_header, timestamp_out_of_tolerance, unknown_key, invalid_key ou invalid_signature.