Webhooks
With the webhooks:manage scope, /v1/webhooks manages the account's webhooks (the same as Settings → Integrations →
Webhooks).
curl -X POST "https://atende.suporteja.com.br/v1/webhooks" -H "Authorization: Bearer $ATENDLLY_API_KEY" -H "Content-Type: application/json" \
-d '{"url": "https://erp.example.com/atendlly", "subscriptions": ["contact_created", "contact_updated", "conversation_status_changed"]}'
The create response carries the signing secret once.
Events: conversation_created, conversation_status_changed, conversation_updated, contact_created,
contact_updated, message_created, message_updated, webwidget_triggered, inbox_created, inbox_updated,
conversation_typing_on, conversation_typing_off. With the Helpdesk: ticket_created, ticket_updated, ticket_status_changed, ticket_sla_warning,
ticket_sla_breached, ticket_csat_received. inbox_id (optional) limits the webhook to one inbox.
Verifying the signature
Each delivery carries three headers: X-Atendlly-Timestamp, X-Atendlly-Delivery (unique delivery id) and
X-Atendlly-Signature. Header names are case-insensitive. The signature is sha256= + HMAC-SHA256(secret, ".").
import hmac, hashlib
def header(headers: dict, name: str) -> str:
return next(v for k, v in headers.items() if k.lower() == name.lower())
def valid(secret: str, headers: dict, body: bytes) -> bool:
timestamp = header(headers, "X-Atendlly-Timestamp")
expected = "sha256=" + hmac.new(secret.encode(), timestamp.encode() + b"." + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header(headers, "X-Atendlly-Signature"))
Reject deliveries whose timestamp is more than 5 minutes old and ignore a repeated X-Atendlly-Delivery. Payloads use the current
event format (not the API v1 shapes) and are not masked.