Use webhooks to trigger requests to your own application when feedback and unsubscribe events occur.
Webhooks are always sent as an HTTP POST
request to the webhook URLs you’ve configured via your Webhooks integration. The details of the activity that triggered the webhook are sent as the body of the HTTP request in JSON format. Every webhook will include an event_type
property that describes what kind of activity triggered the event.
We currently support sending webhook notifications for the following event types:
Type | Description |
---|---|
survey_response.created
|
This occurs the moment a person provides a score. It can take a few minutes to write a comment, so it is unlikely one will be present in this initial payload. |
survey_response.updated
|
This occurs any time the score or comment on a survey response is changed. Responses usually only contain a score when they are first created, so most of the time comments will only appear in a survey_response.updated event.
|
unsubscribe.created
|
This occurs the moment a previously active person unsubcribes from a survey that you sent. |
{
"event_type": "survey_response.updated",
"event_id": "b8d057c59327541d7ec2104c0a9a255ad1997fb00831b9c6bbf09561e6d5cbd0",
"event_data": {
"id": "5435",
"person": {
"id": "5975",
"email": "charlie_gravis@example.com",
"name": "Charlie Gravis",
"created_at": 1732186784
},
"survey_type": "nps",
"score": 9,
"comment": "Your service is fast and flawless!",
"permalink": "https://app.delighted.com/r/5pFDpmlyC8GUc5oxU6USto5VonSKAqOa",
"created_at": 1732186844,
"updated_at": 1732187444,
"person_properties": null,
"notes": [],
"tags": [],
"additional_answers": [
{
"id": "4",
"value": {
"free_response": null,
"scale": null,
"select_one": null,
"select_many": [
{
"id": "DxmjNj",
"text": "Convenience"
},
{
"id": "uNQIig",
"text": "Friendly staff"
}
]
},
"question": {
"id": "enum_z9EvYV",
"type": "select_many",
"text": "What specifically did you enjoy about your experience with us?"
}
},
{
"id": "5",
"value": {
"free_response": null,
"scale": null,
"select_one": {
"id": "tp0Q4K",
"text": "Yes"
},
"select_many": null
},
"question": {
"id": "enum_caUUdY",
"type": "select_one",
"text": "Have you purchased from us in the past?"
}
},
{
"id": "6",
"value": {
"free_response": null,
"scale": 4,
"select_one": null,
"select_many": null
},
"question": {
"id": "integer_buwb3w",
"type": "scale",
"text": "How often do you shop at one of our stores?"
}
},
{
"id": "7",
"value": {
"free_response": "A friend recommended you to me!",
"scale": null,
"select_one": null,
"select_many": null
},
"question": {
"id": "text_BJPEm0",
"type": "free_response",
"text": "How did you hear about us?"
}
}
]
}
}
{
"event_type": "unsubscribe.created",
"event_id": "eb148ac882fadd6c48acfdff638646d939f76204df2283c3f5e2e94cb88a030a",
"event_data": {
"person_id": "5428",
"email": "joseph@johnston.name",
"name": "Joseph Alexander",
"unsubscribed_at": 1732186844
}
}
Name | Type | Description |
---|---|---|
event_type
|
String |
This describes what kind of event triggered this webhook. It is composed of an object type and an action, separated by a period: survey_response.created .
|
event_id
|
String |
The event_id can be used to deduplicate notifications that may be delivered more than once when it’s hard for us to be sure that earlier attempts succeeded. You can ensure that you don’t unnecessarily process requests multiple times by logging each event_id as you process it and checking each event_id is new to ensure you haven’t already processsed it.
|
event_data
|
Map/Dictionary |
This describes the details of the object that triggered the webhook. See the example request bodies above for the details you can expect based on the event’s object type.
For more information on the contents of the |
Name | Example Value |
---|---|
Content-Type
|
application/json
|
User-Agent
|
Delighted Webhook Notifier
|
X-Delighted-API-Version
|
v1
|
X-Delighted-Webhook-Signature
|
|
You should respond with an HTTP status code in the 200 range to indicate that you successfully received the webhook. Any response with a status code outside the 200-299 range, including a redirect, will be treated as a failure, and we will try to deliver the webhook again multiple times over several days.
Every webhook includes an X-Delighted-Webhook-Signature
header that can optionally be used to verify that the request did indeed come from us. The value of this header is composed of two parts, separated by an equal sign: the signature algorithm, and the signature itself.
To validate the signature, you should take the exact HTTP request body as originally transmitted (before decoding the JSON), use your private Delighted API key, and generate an HMAC digest over the request body, using the signature algorithm specified in the header.
Here’s an example in Ruby:
def webhook_signature_valid?(request)
private_api_key = ENV['DELIGHTED_API_KEY']
signature_header = request.headers['X-Delighted-Webhook-Signature']
algorithm, received_signature = signature_header.split('=', 2)
if algorithm != 'sha256'
raise Exception, "Invalid algorithm"
end
expected_signature = OpenSSL::HMAC.hexdigest(
OpenSSL::Digest.new(algorithm), private_api_key, request.body.read
)
return SecurityUtils.secure_compare(received_signature, expected_signature)
end
We recommend that your webhooks use HTTPS URLs so that the customer information delivered to you via webhooks is encrypted while traveling over the internet.