Skip to main content

Webhook di Applicazione

I webhook di applicazione sono chiamate HTTP che Riseact invia al tuo endpoint quando avvengono certi eventi in tutte le organizzazioni che hanno installato la tua applicazione.

A differenza dei webhook di organizzazione, li registri una sola volta sulla partner app. Ogni chiamata indica il dominio dell'organizzazione che ha generato l'evento.

Impostare un webhook

  1. Nel portale partner apri Apps e seleziona la tua applicazione.
  2. Apri la scheda Webhooks e clicca Add Webhook.
  3. Scegli gli eventi e inserisci l'URL HTTPS che riceverà le chiamate POST.
  4. Salva.

Dalla stessa scheda modifichi o elimini i webhook registrati.

Eventi disponibili

EventoDescrizione
supporter.createdUn nuovo sostenitore è stato creato
supporter.updatedUn sostenitore è stato aggiornato
supporter.deletedUn sostenitore è stato eliminato
checkout.createdUn nuovo checkout è stato aperto
checkout.updatedUn checkout è stato aggiornato
checkout.paidUn checkout è stato completato con pagamento
checkout.closedUn checkout è stato chiuso
donation.createdUna nuova donazione è stata creata
donation.updatedUna donazione è stata aggiornata
donation.deletedUna donazione è stata eliminata
donation.revokedUna donazione è stata revocata: a mano, per il rimborso del suo ultimo pagamento o per il pagamento fallito di una donazione singola
payment.createdUn nuovo pagamento è stato registrato
payment.updatedUn pagamento è stato aggiornato
campaign.createdUna nuova campagna è stata creata
campaign.updatedUna campagna è stata aggiornata
campaign.deletedUna campagna è stata eliminata

Consegna delle chiamate

Riseact invia una POST con Content-Type: application/json all'URL registrato. Il payload è lo stesso dei webhook di organizzazione:

  • organization: il dominio dell'organizzazione che ha generato l'evento, da usare per instradarlo;
  • event: il topic dell'evento, per esempio donation.created;
  • object: l'oggetto interessato;
  • idempotency_key: identificativo della chiamata. Può arrivare più volte la stessa chiave: usala per deduplicare.

Esempio (donation.created):

{
  "organization": "org-che-ha-installato-app",
  "object": {
    "id": 229,
    "code": "#1000",
    "state": "pending",
    "amount": 10,
    "frequency": 0,
    "campaign": 29,
    "supporter": 75835,
    "payment_method": "MANUAL"
  },
  "event": "donation.created",
  "idempotency_key": "b1e0c9a2-4f3d-4e2a-9c1b-6a7f8d0e2c34"
}

Gli esempi per gli altri oggetti sono nella pagina dei webhook di organizzazione.

  • Il timeout è di 10 secondi: rispondi subito con 2xx ed elabora in modo asincrono il lavoro pesante.
  • Se la risposta non è 2xx, o non arriva entro il timeout, Riseact ritenta la consegna dopo 1 minuto, 10 minuti, 1 ora, 6 ore e 24 ore, con lo stesso payload e la stessa idempotency_key. Un tentativo ripetuto può quindi arrivare dopo eventi più recenti dello stesso oggetto: confronta update_date con quello che hai salvato e scarta i payload superati.
  • Le chiamate sono firmate con il client secret dell'app: verifica sempre la firma prima di elaborare il payload (vedi Verifica della firma).

Verifica della firma

Le chiamate dei webhook registrati da un'app sono firmate con il client secret dell'app, così puoi verificare che arrivino da Riseact. Lo stesso vale per la chiamata di disinstallazione. La richiesta contiene due header:

  • X-Riseact-Timestamp: istante di invio, in secondi Unix.
  • X-Riseact-Signature: v1= seguito dall'HMAC-SHA256, in esadecimale, della stringa <timestamp>.<corpo>. <corpo> sono i byte grezzi ricevuti, prima di qualunque parsing JSON.

Il prefisso v1= indica lo schema della firma. In futuro l'header potrà contenere più firme separate da virgola (per esempio durante la rotazione del secret): considera valida la richiesta se almeno una firma v1 corrisponde.

Per verificarla:

  1. Ricalcola l'HMAC con il client secret sui byte ricevuti e confrontalo con la firma usando un confronto a tempo costante.
  2. Rifiuta la richiesta se il timestamp si discosta di più di 5 minuti dall'ora corrente, e deduplica su idempotency_key: insieme impediscono di riusare una chiamata intercettata.

Se usi l'SDK Node.js la verifica è già fatta per te. Altrimenti, in Node.js:

const crypto = require("crypto");

function verifyRiseactSignature(rawBody, headers, clientSecret) {
  const timestamp = headers["x-riseact-timestamp"];
  if (!timestamp || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const expected = crypto
    .createHmac("sha256", clientSecret)
    .update(`${timestamp}.`)
    .update(rawBody)
    .digest();

  return (headers["x-riseact-signature"] || "")
    .split(",")
    .map((part) => part.trim().split("="))
    .some(([version, hex]) => {
      if (version !== "v1" || !/^[0-9a-f]{64}$/.test(hex)) return false;
      return crypto.timingSafeEqual(Buffer.from(hex, "hex"), expected);
    });
}

rawBody devono essere i byte ricevuti, non il JSON riserializzato: con Express usa l'opzione verify di express.json() per conservarli, oppure express.raw({ type: "application/json" }) sulla rotta del webhook.

I webhook registrati dal portale partner sono firmati. Quelli che un'app registra su una singola organizzazione tramite API, con il proprio token, sono firmati anch'essi. Un webhook creato prima dell'introduzione della firma resta non firmato finché l'app non lo aggiorna o lo registra di nuovo.

Disinstallazione dell'app

Quando un'organizzazione disinstalla la tua app, o viene eliminata, Riseact revoca i token dell'app e invia una POST firmata a un percorso fisso:

<app_url>/webhooks/app-uninstalled

<app_url> è l'URL dell'app impostato nel portale partner. Non serve registrare nulla: la chiamata non compare tra i webhook dell'app e non si può disattivare. Usala per cancellare i dati e le credenziali che conservi per quell'organizzazione.

{
  "organization": "org-che-ha-disinstallato",
  "event": "app.uninstalled",
  "object": {
    "id": 42,
    "client_id": "<client id della tua app>",
    "organization": "org-che-ha-disinstallato",
    "reason": "app_uninstalled",
    "uninstalled_at": "2026-10-14T12:00:00.000000+00:00"
  },
  "idempotency_key": "6f1d2c3b-8a9e-4f70-b1c2-d3e4f5a6b7c8"
}
  • reason vale app_uninstalled se l'organizzazione ha disinstallato l'app, organization_deleted se l'organizzazione è stata eliminata.
  • Verifica sempre la firma prima di cancellare qualcosa.
  • Rispondi 2xx solo quando la cancellazione è riuscita, così in caso di errore Riseact ritenta come per gli altri webhook.
  • La chiamata può arrivare più volte, e la tua app potrebbe aver già cancellato i dati: gestiscila in modo idempotente.
  • Quando la chiamata arriva i token sono già revocati, quindi non puoi più interrogare le API per quell'organizzazione.
  • Le app private di un'organizzazione eliminata vengono eliminate con lei, e per loro la chiamata non viene inviata.

Con l'SDK Node.js il percorso è gestito dall'SDK: implementa auth.onUninstall per cancellare i dati, le credenziali vengono rimosse in automatico.

Registro degli eventi

La scheda Events dell'app elenca ogni tentativo di consegna, con organizzazione, evento, payload, stato HTTP (o errore di connessione) e corpo della risposta.

Una consegna fallita si può rilanciare a mano dal dettaglio dell'evento.

Differenza rispetto ai webhook di organizzazione

Webhook di applicazioneWebhook di organizzazione
AmbitoTutte le org che installano l'appUna sola organizzazione
Dove si registranoPortale partner, scheda WebhooksAdmin dell'organizzazione, app privata
Chi li usaPartner app di terze partiAutomazioni e integrazioni interne
PayloadUguale (include organization)Uguale (include organization)

Fonte: https://dev.riseact.org/docs/partner-apps/application-webhooks. Copia automatica da dev.riseact.org: non modificare qui, le modifiche vanno fatte sulla documentazione Docusaurus.