Skip to main content

Webhook Events Reference

This page documents all webhook events, their triggers, and payload structures.

Event Flow

Common Payload Structure

All webhook payloads share a common structure:

Base payload structure
{
"event": "EVENT_TYPE",
"timestamp": "2024-01-15T10:30:00Z",
"webhookId": "wh_abc123",
"departmentId": "dept_xyz789",
"data": { /* Event-specific data */ }
}

Common Fields

FieldTypeDescription
eventstringThe event type that triggered this webhook
timestampstringISO 8601 timestamp of when the event occurred
webhookIdstringUnique identifier for the webhook configuration
departmentIdstringThe department where the event occurred
dataobjectEvent-specific payload data

SURVEY_COMPLETED

Triggered when a respondent submits a completed survey response.

When It Fires

  • Respondent clicks submit on the final page
  • All required questions have been answered
  • Survey response is successfully saved
📦 Full Payload Example (click to expand)
SURVEY_COMPLETED payload
{
"event": "SURVEY_COMPLETED",
"timestamp": "2024-01-15T10:30:00Z",
"webhookId": "wh_abc123",
"departmentId": "dept_xyz789",
"data": {
"surveyId": "survey_123",
"surveyName": "Customer Satisfaction Survey",
"responseId": "resp_456",
"collectorId": "col_789",
"collectorType": "email",
"completedAt": "2024-01-15T10:30:00Z",
"contact": {
"id": "contact_001",
"email": "customer@example.com",
"phone": "+1234567890",
"customFields": {
"firstName": "John",
"lastName": "Doe"
}
},
"responses": [
{
"questionId": "q1",
"questionTitle": "How satisfied are you?",
"questionType": "rating",
"answer": 9
},
{
"questionId": "q2",
"questionTitle": "Would you recommend us?",
"questionType": "boolean",
"answer": true
},
{
"questionId": "q3",
"questionTitle": "Additional comments",
"questionType": "text",
"answer": "Great service!"
}
],
"metadata": {
"ipAddress": "192.168.1.1",
"userAgent": "Mozilla/5.0...",
"duration": 245,
"language": "en"
}
}
}

Data Fields

FieldTypeDescription
surveyIdstringUnique survey identifier
surveyNamestringName of the survey
responseIdstringUnique response identifier
collectorIdstringCollector that gathered this response
collectorTypestringType: email, sms, whatsapp, web, widget
completedAtstringISO 8601 completion timestamp
contactobjectRespondent contact information (if available)
responsesarrayArray of question-answer pairs
metadataobjectAdditional response metadata

Handler Examples

server.js
const express = require('express');
const app = express();

app.post('/webhooks/pollarix', express.json(), (req, res) => {
const { event, data } = req.body;

if (event === 'SURVEY_COMPLETED') {
// Extract NPS score
const npsQuestion = data.responses.find(r => r.questionType === 'rating');
const score = npsQuestion?.answer;

console.log(`New response! Score: ${score}, Email: ${data.contact.email}`);

// Sync to your CRM
syncToCRM(data.contact.email, score);
}

res.status(200).send('OK');
});

app.listen(3000);

SURVEY_STATUS_CHANGED

Triggered when a survey's status is modified.

When It Fires

  • Survey is activated (draft → active)
  • Survey is deactivated (active → inactive)
  • Survey is closed
  • Survey is reopened
📦 Full Payload Example
SURVEY_STATUS_CHANGED payload
{
"event": "SURVEY_STATUS_CHANGED",
"timestamp": "2024-01-15T14:00:00Z",
"webhookId": "wh_abc123",
"departmentId": "dept_xyz789",
"data": {
"surveyId": "survey_123",
"surveyName": "Customer Satisfaction Survey",
"previousStatus": "draft",
"newStatus": "active",
"changedBy": {
"userId": "user_456",
"email": "admin@company.com"
},
"changedAt": "2024-01-15T14:00:00Z"
}
}

Status Values

StatusDescription
draftSurvey is being edited, not accepting responses
activeSurvey is live and accepting responses
inactiveSurvey is paused, not accepting responses
closedSurvey is permanently closed

Handler Examples

Notify on status change
if (event === 'SURVEY_STATUS_CHANGED' && data.newStatus === 'active') {
await slack.postMessage({
channel: '#surveys',
text: `Survey "${data.surveyName}" is now live!`
});
}

// Archive data when survey closes
if (data.newStatus === 'closed') {
await archiveSurveyData(data.surveyId);
}

COUPON_REDEEMED

Triggered when a coupon is distributed to a survey respondent.

When It Fires

  • Automation workflow distributes a coupon
  • Coupon is successfully assigned to a contact
  • Coupon delivery method is executed (email, SMS, or WhatsApp)
📦 Full Payload Example
COUPON_REDEEMED payload
{
"event": "COUPON_REDEEMED",
"timestamp": "2024-01-15T10:35:00Z",
"webhookId": "wh_abc123",
"departmentId": "dept_xyz789",
"data": {
"couponId": "coupon_123",
"couponCode": "SAVE20NOW",
"couponGroupId": "group_456",
"couponGroupName": "January Promotions",
"responseId": "resp_789",
"surveyId": "survey_123",
"contact": {
"id": "contact_001",
"email": "customer@example.com",
"phone": "+1234567890"
},
"deliveryMethod": "email",
"deliveredAt": "2024-01-15T10:35:00Z",
"expiresAt": "2024-02-15T23:59:59Z"
}
}

Data Fields

FieldTypeDescription
couponIdstringUnique coupon identifier
couponCodestringThe actual coupon code
couponGroupIdstringCoupon group identifier
couponGroupNamestringName of the coupon group
responseIdstringSurvey response that triggered the coupon
surveyIdstringAssociated survey
contactobjectRecipient contact information
deliveryMethodstringHow coupon was sent: email, sms, whatsapp
deliveredAtstringISO 8601 delivery timestamp
expiresAtstringCoupon expiration date

Response Handling

Important

Always respond quickly (< 5 seconds) to webhook requests. Process data asynchronously.

Response CodeMeaningPollarix Action
2xx✅ SuccessDelivery confirmed
4xx❌ Client errorWill not retry
5xx⚠️ Server errorMay retry
Timeout⏱️ No responseMay retry

Idempotent Handler Pattern

Idempotent webhook handler
const processedEvents = new Set();

app.post('/webhooks/pollarix', (req, res) => {
// Create unique key to prevent duplicate processing
const eventKey = `${req.body.webhookId}-${req.body.timestamp}`;

if (processedEvents.has(eventKey)) {
return res.status(200).send('Already processed');
}

processedEvents.add(eventKey);

// Process webhook async
processWebhookAsync(req.body);

res.status(200).send('OK');
});

Next Steps

Was this page helpful?