Webhooks Integration Guide
Webhooks
Receive real-time HTTP POST notifications when users enter your giveaway, complete tasks, or finish all entries. Available on Enterprise plans.
Overview
SweepWidget provides two ways to receive real-time event data from your giveaways:
- Server-side webhooks – HTTP POST requests sent from our server to yours. Work on both embedded widgets and hosted landing pages. Best for backend workflows like CRM syncing, email triggers, and database updates.
- Client-side JavaScript callbacks – Browser events fired on the page where the widget is loaded. Best for frontend actions like firing tracking pixels, showing custom UI, or triggering analytics events.
Both systems fire on the same three events and return the same data. You can use one or both depending on your needs.
On this page:
- Setup
- Events
- Payload Format
- Request Headers
- Signature Verification
- JavaScript Callbacks
- Signing Secret
- Troubleshooting
Setup
Server-side webhooks
- Go to Integrations in your dashboard and click the Webhooks card.
- Enter your endpoint URL (must use HTTPS) and click Save.
- Copy the Signing Secret to verify webhook signatures on your server.
Use the Send Test button to send a test payload and confirm your endpoint is receiving requests.
Note: Webhooks are configured at the account level. Once set up, they fire for all giveaways on your account.
JavaScript callbacks
No dashboard configuration needed. Add an event listener to the page where your SweepWidget is embedded. See the JavaScript Callbacks section below for code examples.
Events
All three events fire automatically. There is no per-event toggle. Both webhooks and JS callbacks fire on the same events.
| Event | Fires when |
|---|---|
entry_submitted |
A user submits the initial entry form (email, name, etc.) |
task_completed |
A user completes a bonus entry task (follow, visit, share, etc.) |
all_entries_completed |
A user has completed every available task in the giveaway |
Payload Format
Both webhooks and JS callbacks return the same data for each event. Webhooks wrap the data in an event + data + timestamp envelope. JS callbacks provide the data directly in e.detail.
entry_submitted
{
"event": "entry_submitted",
"data": {
"competition_id": "12345",
"competition_url": "my-giveaway",
"user": {
"email": "[email protected]",
"name": "Jane Smith",
"phone": "+1234567890",
"birthday": "1990-01-15"
},
"custom_fields": [
{
"entry_id": "101",
"field_type": "text_input",
"label": "Company Name",
"value": "Acme Corp"
}
],
"entries": 5,
"referral_url": "https://sweepwidget.com/c/my-giveaway-abc123",
"timestamp": "2026-03-04T12:00:00+00:00"
},
"timestamp": "2026-03-04T12:00:00+00:00"
}
task_completed
{
"event": "task_completed",
"data": {
"competition_id": "12345",
"competition_url": "my-giveaway",
"user": {
"email": "[email protected]",
"name": "Jane Smith"
},
"task": {
"entry_id": "67",
"entry_method": "Visit a page",
"entry_group_id": "3"
},
"entries": 10,
"remaining_tasks": 2,
"timestamp": "2026-03-04T12:01:00+00:00"
},
"timestamp": "2026-03-04T12:01:00+00:00"
}
all_entries_completed
{
"event": "all_entries_completed",
"data": {
"competition_id": "12345",
"competition_url": "my-giveaway",
"user": {
"email": "[email protected]",
"name": "Jane Smith"
},
"entries": 25,
"timestamp": "2026-03-04T12:02:00+00:00"
},
"timestamp": "2026-03-04T12:02:00+00:00"
}
Request Headers
Each webhook HTTP request includes these headers:
| Header | Description |
|---|---|
Content-Type |
application/json |
X-SweepWidget-Signature |
HMAC-SHA256 signature of the payload body, prefixed with sha256= |
X-SweepWidget-Event |
The event name (e.g. entry_submitted) |
User-Agent |
SweepWidget-Webhook/1.0 |
Signature Verification
Always verify the X-SweepWidget-Signature header to confirm the request came from SweepWidget. Compute an HMAC-SHA256 hash of the raw request body using your signing secret and compare it to the signature in the header.
PHP
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SWEEPWIDGET_SIGNATURE'] ?? '';
$secret = 'whsec_your_signing_secret';
$expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);
if (!hash_equals($expected, $signature)) {
http_response_code(401);
exit('Invalid signature');
}
$event = json_decode($payload, true);
// Process the event...
Node.js
const crypto = require('crypto');
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-sweepwidget-signature'] || '';
const secret = 'whsec_your_signing_secret';
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(req.body)
.digest('hex');
if (signature !== expected) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
// Process the event...
res.sendStatus(200);
});
JavaScript Callbacks
SweepWidget fires client-side JavaScript events whenever a user enters your giveaway, completes a task, or finishes all entries. These events work on both embedded widgets (via postMessage relay from the iframe to the parent page) and hosted landing pages (via CustomEvent on the window).
No dashboard configuration is required. Just add a listener to the page where your widget is embedded. The event data is identical to the webhook payload data.
Method 1: Individual event listeners
Listen for specific events by name. The event data is available in e.detail.
window.addEventListener('sweepwidget.entry_submitted', function(e) {
console.log(e.detail.user.email); // "[email protected]"
console.log(e.detail.user.name); // "Jane Smith"
console.log(e.detail.entries); // 5
console.log(e.detail.custom_fields); // [{entry_id, field_type, label, value}]
console.log(e.detail.referral_url); // "https://sweepwidget.com/c/..."
});
window.addEventListener('sweepwidget.task_completed', function(e) {
console.log(e.detail.task.entry_method); // "Visit a page"
console.log(e.detail.remaining_tasks); // 2
});
window.addEventListener('sweepwidget.all_entries_completed', function(e) {
console.log(e.detail.entries); // 25
});
Method 2: Catch-all event listener
Listen for all SweepWidget events with a single listener. The event name and data are in e.detail.event and e.detail.data.
window.addEventListener('sweepwidget', function(e) {
console.log('Event:', e.detail.event); // "sweepwidget.entry_submitted"
console.log('Data:', e.detail.data); // {competition_id, user, entries, ...}
});
Method 3: Global callback function
Define a global function that will be called for every event. This works even if you add it before the SweepWidget script loads.
window.SweepWidgetCallback = function(eventName, eventData) {
// eventName: "sweepwidget.entry_submitted"
// eventData: {competition_id, user, entries, custom_fields, ...}
console.log(eventName, eventData);
};
Example: Fire a Meta/Facebook pixel event on entry
window.addEventListener('sweepwidget.entry_submitted', function(e) {
fbq('track', 'Lead', {
content_name: e.detail.competition_url,
value: e.detail.entries,
currency: 'USD'
});
});
Example: Google Analytics event on entry
window.addEventListener('sweepwidget.entry_submitted', function(e) {
gtag('event', 'giveaway_entry', {
competition_id: e.detail.competition_id,
email: e.detail.user.email
});
});
Embedded widgets: Events are sent from the iframe to the parent page via postMessage. The SweepWidget embed script automatically relays them as CustomEvents on the parent window, so your listeners work without any extra setup.
Signing Secret
A signing secret is generated automatically when you first save a webhook URL. You can regenerate it at any time from the Webhooks settings page by clicking Regenerate Secret.
Important: Regenerating your secret immediately invalidates the old one. Update your server with the new secret right away to avoid rejected webhooks.
Troubleshooting
| Issue | Solution |
|---|---|
| Not receiving webhooks | Confirm your URL starts with https:// and your endpoint returns a 2xx status code. Use the Test button to verify. |
| Signature mismatch | Make sure you are hashing the raw request body (not a parsed/re-serialized version). Check that your secret matches the one shown in settings. |
| Timeouts | SweepWidget waits up to 5 seconds for a response. Return a 200 immediately and process the data asynchronously if your logic takes longer. |
| JS callbacks not firing (embedded) | Make sure you are using the SweepWidget <script> embed code, not a raw iframe. The embed script handles the postMessage relay. Add your event listeners before the embed script loads. |
| JS callbacks not firing (hosted) | On hosted landing pages, JS callbacks fire as CustomEvents on the window. You need to inject custom JavaScript on the page to listen for them. Verify your account is on an Enterprise plan. |