Webhooks
Verify and parse outbound sms.delivered/sms.failed events. The signature is an HMAC-SHA256 hex digest of the exact raw body in the X-SendAfrica-Signature header.
func webhookHandler(client *sendafrica.Client) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
signature := r.Header.Get("X-SendAfrica-Signature")
event, err := client.Webhooks.Parse(body, signature, "") // "" uses the client-level secret
if err != nil {
http.Error(w, "invalid signature", http.StatusUnauthorized)
return
}
fmt.Println(event.Type, event.MessageID, event.Data)
// durable work here, then acknowledge
w.WriteHeader(http.StatusOK)
}
}What the parser guarantees
- Verify without parsing:
client.Webhooks.Verify(payload, signature, secret)or the standalonesendafrica.VerifyWebhookSignature(payload, signature, secret). - Parse tolerantly:
ParseWebhookaccepts both envelope spellings (type/message_idorstatus) and only ever emits the parsed event after a valid signature. - Constant-time comparison: signature comparison uses
hmac.Equal.
Correct response semantics
- Return
2xxonly after the event is durably processed — persist or queue beforew.WriteHeader(http.StatusOK). - Ack fast, process heavy work asynchronously.
- Deduplicate on
(MessageID, Type)— retries can deliver duplicates.
See Webhooks for the full contract, retry backoff, and endpoint-management API.
Last updated on