Português · English

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.