Vai al contenuto
WbizTool

API v2 (beta)

Webhook

Un endpoint del webhook è un URL sul tuo server che WbizTool chiama quando succede qualcosa a un messaggio: è stato inviato, non è riuscito, è stato annullato o è scaduto. Ricevi la notizia subito invece di dover interrogare l'API, e ogni richiesta è firmata, così puoi verificare che arrivi da WbizTool.

OperazioneEndpointScope
Aggiungere un endpointPOST /api/v2/webhooksmessages:read
Elencare gli endpointGET /api/v2/webhooksmessages:read
Ottenere un endpointGET /api/v2/webhooks/{id}messages:read
Rimuovere un endpointDELETE /api/v2/webhooks/{id}messages:read
Sostituire il secret di firmaPOST /api/v2/webhooks/{id}/rotate-secretmessages:read
Inviare un evento di testPOST /api/v2/webhooks/{id}/testmessages:read

Gli endpoint appartengono allo spazio di lavoro e ricevono gli eventi di tutti i suoi messaggi, chiunque li abbia inviati: l'API, la dashboard, le campagne, i promemoria o le integrazioni. Per questo una chiave limitata ad alcuni numeri non può gestirli: ogni chiamata risponde 403 number_not_allowed.

Eventi#

TipoQuando
message.sentUn messaggio è partito dal tuo numero.
message.failedNon è stato possibile inviare un messaggio; error.message spiega perché.
message.cancelledUn messaggio in attesa è stato annullato: con l'API, dalla dashboard, o perché il suo numero o la sua campagna è stata rimossa.
message.expiredUn messaggio non è stato inviato prima del suo expires_at.
pingUn evento di test che hai richiesto.

Gli eventi per i numeri (collegato, disconnesso) e per i messaggi in arrivo arriveranno più avanti. Le spunte di consegna e di lettura non inviano eventi; ottieni il messaggio per vederle.

Aggiungere un endpoint#

POSThttps://wbiztool.com/api/v2/webhooks

Corpo: JSON (application/json)

Body

urlstringobbligatorio

Il tuo endpoint: un indirizzo https:// pubblico, fino a 500 caratteri. Gli indirizzi http://, privati e locali (come localhost o 192.168.x.x) vengono rifiutati.

eventsarray of stringsfacoltativo

I tipi di evento che riceve: uno qualsiasi tra message.sent, message.failed, message.cancelled e message.expired. Predefinito: tutti e quattro. ping arriva sempre quando ne richiedi uno.

descriptionstringfacoltativo

Una nota per te, fino a 100 caratteri, ad esempio Order system.

Uno spazio di lavoro può avere fino a 5 endpoint. La risposta è 201 con l'endpoint e il suo secret di firma, mostrato solo questa volta. Conservalo dove il tuo ricevitore può leggerlo, ad esempio in una variabile d'ambiente. Le risposte successive mostrano solo secret_last4; se perdi il secret, sostituiscilo.

curl -X POST https://wbiztool.com/api/v2/webhooks \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/wbiztool/events",
    "events": ["message.sent", "message.failed"],
    "description": "Order system"
  }'

Risposta (201):

{
  "id": 41,
  "url": "https://example.com/wbiztool/events",
  "description": "Order system",
  "events": ["message.sent", "message.failed"],
  "secret_last4": "9c1e",
  "active": true,
  "disabled_reason": null,
  "created_at": "2026-10-18T11:20:05.733Z",
  "last_delivery": null,
  "secret": "3f0b…9c1e"
}

Il vero secret è composto da 64 caratteri esadecimali. Un nuovo tentativo di questa richiesta con lo stesso Idempotency-Key non aggiunge un secondo endpoint, e la sua risposta omette il secret.

Errori durante l'aggiunta di un endpoint#

HTTPCodiceQuando
400validation_failedurl manca o è troppo lungo, events è vuoto o contiene un tipo sconosciuto, oppure un campo è sconosciuto
403webhook_limit_reachedLo spazio di lavoro ha già 5 endpoint
403number_not_allowedLa chiave è limitata ad alcuni numeri
422invalid_webhook_urlurl non è un indirizzo https:// pubblico

Elencare gli endpoint#

GEThttps://wbiztool.com/api/v2/webhooks

Gli endpoint dello spazio di lavoro che ricevono eventi, dal più vecchio, in un'unica lista data.

curl https://wbiztool.com/api/v2/webhooks \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY"

La lista omette gli endpoint che si sono fermati. Anche i Proprietari vedono gli endpoint, e possono rimuoverli, in Impostazioni → Chiavi API sotto Endpoint dei webhook.

Ottenere un endpoint#

GEThttps://wbiztool.com/api/v2/webhooks/{id}

Un singolo endpoint. last_delivery mostra com'è andata la sua consegna più recente. Un endpoint che non esiste o è stato rimosso risponde 404 webhook_not_found; uno fermato viene mostrato con active: false.

Rimuovere un endpoint#

DELETEhttps://wbiztool.com/api/v2/webhooks/{id}

Non gli viene più inviato nulla, compresi i nuovi tentativi ancora in attesa. La risposta è {"id": 41, "deleted": true}.

Sostituire il secret di firma#

POSThttps://wbiztool.com/api/v2/webhooks/{id}/rotate-secret

Crea un nuovo secret per l'endpoint. La risposta è 200 con l'endpoint e il suo nuovo secret, mostrato solo questa volta. Il vecchio secret smette subito di funzionare: gli eventi inviati da questo momento sono firmati con quello nuovo, compresi i nuovi tentativi di eventi precedenti. Aggiorna subito il tuo ricevitore.

curl -X POST https://wbiztool.com/api/v2/webhooks/41/rotate-secret \
  -H "Authorization: Bearer $WBIZTOOL_API_KEY"

Inviare un evento di test#

POSThttps://wbiztool.com/api/v2/webhooks/{id}/test

Mette in coda un evento ping verso questo endpoint, firmato come ogni evento, così puoi provare il tuo ricevitore. La risposta è 202:

{ "event_id": "evt_8a2f4c1d9b7e6a5f4c3b2a19", "type": "ping", "queued": true }

Il tuo endpoint riceve:

{
  "id": "evt_8a2f4c1d9b7e6a5f4c3b2a19",
  "type": "ping",
  "created_at": "2026-10-18T11:21:40.002Z",
  "data": { "webhook_id": 41 }
}

Il payload dell'evento#

Ogni evento è un POST con un body JSON:

{
  "id": "evt_c41d7e2a9f3b8c6d5e4f3a21",
  "type": "message.sent",
  "created_at": "2026-10-18T10:15:09.912Z",
  "data": {
    "message": {
      "id": 9817263,
      "status": "sent",
      "from": { "id": 101, "phone": "919800000000", "platform": "whatsapp" },
      "to": { "phone": "+919876543210", "contact_id": 991 },
      "text": "Hi Asha, your order #1042 is ready.",
      "media": null,
      "send_at": null,
      "expires_at": null,
      "created_at": "2026-10-18T10:15:02.311Z",
      "sent_at": "2026-10-18T10:15:09.870Z",
      "error": null
    }
  }
}
CampoDescrizione
idL'id dell'evento, evt_ seguito da 24 caratteri. Lo stesso evento mantiene il suo id a ogni nuovo tentativo.
typeUno dei tipi di evento.
created_atQuando si è verificato l'evento.
data.messagePer gli eventi message.*: il Message com'era in quel momento. Un media.url al suo interno funziona per almeno 26 ore.
data.webhook_idPer ping: l'id dell'endpoint.

Header:

HeaderValore
Content-Typeapplication/json
User-AgentWbizTool-Webhooks/2
WbizTool-Event-IdL'id dell'evento, uguale a ogni nuovo tentativo
WbizTool-TimestampQuando è stato inviato questo tentativo, in secondi Unix, ad esempio 1792310409
WbizTool-Signaturev1= seguito dall'HMAC-SHA256 esadecimale di <timestamp>.<raw body>, calcolato con il secret dell'endpoint

Verificare la firma#

Controlla ogni richiesta prima di fidarti: calcola la firma dal body grezzo (prima che il tuo framework analizzi il JSON), confrontala con l'header in tempo costante e rifiuta i timestamp che si discostano di più di 5 minuti, così una vecchia richiesta non può essere riprodotta. È lo stesso schema delle firme dei webhook dell'API v1, con il secret proprio dell'endpoint.

Poi usa WbizTool-Event-Id per scartare i duplicati: lo stesso evento può arrivare più di una volta, ad esempio quando la tua risposta è andata persa e abbiamo riprovato.

import hashlib, hmac, json, os, time

SECRET = os.environ["WBIZTOOL_WEBHOOK_SECRET"]

def verify(secret: str, body: bytes, headers) -> bool:
    ts, sig = headers.get("WbizTool-Timestamp", ""), headers.get("WbizTool-Signature", "")
    if not ts.isdigit() or abs(time.time() - int(ts)) > 300:
        return False
    mac = "v1=" + hmac.new(secret.encode(), ts.encode() + b"." + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(mac, sig)

# Flask
from flask import Flask, request

app = Flask(__name__)
seen = set()  # use your database in production

@app.post("/wbiztool/events")
def events():
    body = request.get_data()  # the raw bytes
    if not verify(SECRET, body, request.headers):
        return "", 401
    event_id = request.headers["WbizTool-Event-Id"]
    if event_id in seen:
        return "", 200  # a repeat: already handled
    seen.add(event_id)
    event = json.loads(body)
    if event["type"] == "message.failed":
        message = event["data"]["message"]
        print("Failed:", message["id"], message["error"]["message"])
    return "", 200

In Django passa request.body e request.headers.

Rispondi subito con 2xx, poi esegui il lavoro lento in seguito (ad esempio in una coda).

Nuovi tentativi#

  • Rispondi con un qualsiasi 2xx entro 10 secondi. Tutto il resto è un errore: un altro codice di stato (4xx compreso), nessuna risposta entro 10 secondi o nessuna connessione entro 3. I reindirizzamenti vengono seguiti, al massimo 3, e ognuno deve portare a un indirizzo pubblico.
  • Una consegna non riuscita viene ritentata dopo 1, 5 e 15 minuti, poi dopo 1, 2, 4, 8 e 8 ore: 9 tentativi in circa 23 ore. Dopo l'ultimo, quell'evento viene scartato.
  • Il nuovo tentativo ha lo stesso body e lo stesso WbizTool-Event-Id, con un nuovo WbizTool-Timestamp e una nuova firma.
  • L'ordine non è garantito. Un message.sent ritentato può arrivare dopo un evento successivo. Quando l'ordine conta, usa lo status del messaggio, oppure ottieni il messaggio.

last_delivery sull'endpoint mostra com'è andata la consegna più recente: state (pending, delivered o failed), lo status_code con cui ha risposto il tuo server e quando è stato creato l'evento.

Quando gli endpoint si fermano#

Un endpoint smette di ricevere eventi quando succede una di queste cose. Resta in GET /webhooks con active: false e un disabled_reason, così puoi vedere il motivo; si può ancora leggere e rimuovere, ma non provare né dotare di un nuovo secret (404).

  • Non riesce da 24 ore. Se per 24 ore non gli è stato consegnato nulla mentre le sue consegne continuavano a non riuscire, viene disattivato e i suoi nuovi tentativi in attesa vengono scartati. Impostazioni → Chiavi API lo mostra allora come Disattivato. Sistema il tuo server, poi aggiungi di nuovo l'endpoint.
  • La chiave che lo ha creato viene revocata o scade. Revocare una chiave ferma tutto ciò che ha configurato. Aggiungi di nuovo l'endpoint con un'altra chiave.
  • Viene rimosso, con Rimuovere un endpoint o in Impostazioni → Chiavi API.

Gli endpoint fermati non contano nei 5.

L'oggetto endpoint del webhook#

CampoTipoDescrizione
idintegerL'id dell'endpoint.
urlstringDove vengono inviati gli eventi.
descriptionstringLa tua nota; "" se non ce n'è una.
eventsarrayI tipi di evento che riceve.
secretstringIl secret di firma: solo nelle risposte di Aggiungere un endpoint e Sostituire il secret di firma.
secret_last4stringGli ultimi 4 caratteri del secret, per capire quale hai.
activebooleanfalse quando non riceve più eventi – vedi Quando gli endpoint si fermano.
disabled_reasonstring or nullPerché si è fermato (errori per 24 ore, oppure la chiave che lo ha creato è stata revocata o è scaduta); null mentre è attivo.
created_atstringQuando è stato aggiunto.
last_deliveryobject or nullL'ultima consegna tentata: state, status_code (o null quando il tuo server non ha risposto) e created_at. null prima della prima.

Pagine correlate#