Uplup Logo

Webhooks | Real-time Event Notifications

What are Webhooks?

Webhooks let you receive real-time HTTP notifications when events happen in your Uplup forms and quizzes. Instead of polling the API, webhooks push data to your server the moment something occurs — a submission is received, a quiz is completed, a form is published, and more.

Uplup webhooks follow the same industry-standard patterns used by Stripe, GitHub, and Typeform: HTTPS delivery, HMAC-SHA256 signatures for verification, and structured JSON payloads.

Plan Requirements

Webhooks are available on Business and Scale plans only.

Plan Webhooks Events
Free Not available
Starter Not available
Pro Not available
Business 10 webhooks All 19 events
Scale 100 webhooks All 19 events

Setting Up Webhooks

You can manage webhooks in two ways:

  1. Dashboard — Go to Account → API Integrations → Webhooks tab
  2. REST API — Use the /api/v1/webhooks endpoints with a Bearer token

Creating a Webhook

  1. Navigate to API Integrations in your account settings
  2. Click the Webhooks tab
  3. Click Create Webhook
  4. Enter your HTTPS endpoint URL (HTTPS is required)
  5. Select the event type you want to subscribe to
  6. Optionally filter to a specific form
  7. Click Create

Important: When you create a webhook, a signing secret is displayed once. Copy and save it securely — you’ll need it to verify webhook signatures. It cannot be retrieved again.

Event Types

Uplup supports 19 webhook events organized into 5 categories. Each webhook subscribes to one event type.

Form Lifecycle

Event Description
form.created A new form or quiz was created
form.updated Form settings were modified
form.deleted A form was deleted
form.published A form was published (made live)
form.unpublished A form was taken offline
form.cloned A form was duplicated

Submissions

Event Description
submission.created A new form response was received
submission.completed A multi-step submission was completed (reserved)
submission.deleted A submission was deleted

Quiz

Event Description
quiz.completed A quiz was scored and results generated
quiz.passed A quiz taker met the passing score threshold
quiz.failed A quiz taker did not meet the passing score
quiz.timer_expired A quiz timer ran out before the taker could finish

Fields

Event Description
field.created A field was added to a form
field.updated A field’s properties were modified
field.deleted A field was removed from a form

Responses

Event Description
response.started A user began filling out a form (first interaction per session)
response.page_completed A user completed a form page (with field data for that page)
response.abandoned A user left the form without completing it

Payload Format

Every webhook delivery sends a JSON payload with this structure:

{
  "event": "submission.created",
  "webhook_id": 42,
  "form_id": "abc12345",
  "timestamp": "2026-03-09T12:00:00Z",
  "data": {
    "submission_id": "sub_789",
    "form_id": "abc12345",
    "fields": {
      "email": "user@example.com",
      "name": "Jane Smith"
    }
  }
}

Request Headers

Each webhook request includes these headers:

Header Description
Content-Type application/json
X-Uplup-Signature HMAC-SHA256 hex digest of the request body
X-Webhook-Event The event type (e.g., submission.created)
X-Webhook-ID Unique ID of the webhook subscription
User-Agent Uplup-Webhooks/1.0

Verifying Webhook Signatures

Always verify the X-Uplup-Signature header to confirm the request came from Uplup. The signature is an HMAC-SHA256 hex digest of the raw request body, using your webhook’s signing secret as the key.

JavaScript (Node.js)

const crypto = require('crypto');

function verifyWebhook(body, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(body, 'utf8')
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// Express.js example
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-uplup-signature'];
  if (!verifyWebhook(req.body, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  const event = JSON.parse(req.body);
  console.log('Received:', event.event);
  res.status(200).send('OK');
});

Python

import hmac
import hashlib

def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode('utf-8'),
        body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

# Flask example
@app.route('/webhook', methods=['POST'])
def webhook():
    signature = request.headers.get('X-Uplup-Signature', '')
    if not verify_webhook(request.data, signature, WEBHOOK_SECRET):
        return 'Invalid signature', 401
    event = request.get_json()
    print(f"Received: {event['event']}")
    return 'OK', 200

PHP

<?php
$body = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_UPLUP_SIGNATURE'] ?? '';
$secret = getenv('WEBHOOK_SECRET');

$expected = hash_hmac('sha256', $body, $secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}

$event = json_decode($body, true);
error_log('Received: ' . $event['event']);
http_response_code(200);
echo 'OK';

Delivery Policy

  • Timeout: 5 seconds — your endpoint must respond within 5 seconds
  • Success: Any 2xx HTTP status code is considered successful delivery
  • HTTPS required: Webhook URLs must use HTTPS (HTTP is rejected)
  • No automatic retries: Failed deliveries are logged but not automatically retried. Use the “Send Test” button to re-test
  • Delivery logs: The last 20 deliveries per webhook are stored with status code, response time, and error details

Testing Webhooks

You can test your webhook endpoint directly from the dashboard:

  1. Find your webhook in the Webhooks tab
  2. Click Send Test
  3. A sample event payload will be sent to your URL
  4. The result shows the HTTP status code and response time

Test events are rate-limited to 5 per minute per webhook. Test deliveries appear in the delivery log just like real events.

Managing Webhooks

Pausing a Webhook

Toggle the switch next to any webhook to pause or resume it. Paused webhooks do not receive any events.

Deleting a Webhook

Click the delete button and confirm to remove a webhook. Deleted webhooks stop receiving events immediately.

Filtering by Form

When creating a webhook, you can optionally select a specific form. The webhook will only fire for events related to that form. Leave the filter empty to receive events for all forms.

Security Best Practices

  • Always verify signatures — Never process a webhook payload without verifying the X-Uplup-Signature header
  • Use HTTPS — All webhook URLs must use HTTPS. Uplup rejects HTTP endpoints
  • Store secrets securely — Keep your signing secret in environment variables, never in source code
  • Respond quickly — Process webhooks asynchronously. Return a 200 immediately, then handle the event in a background job
  • Handle duplicates — Use the webhook_id and timestamp to detect duplicate deliveries

FAQ

Which plans support webhooks?

Webhooks are available on Business (10 webhooks) and Scale (100 webhooks) plans. Free, Starter, and Pro plans do not include webhook access.

Can I subscribe to multiple events?

Each webhook subscribes to one event type. To receive multiple event types, create separate webhooks — one per event. This gives you fine-grained control over which events go to which endpoints.

Are webhook deliveries retried?

No. Failed deliveries are logged with error details, but not automatically retried. You can re-test manually using the Send Test button, or check delivery logs to diagnose issues.

Can I filter webhooks to specific forms?

Yes. When creating a webhook, you can select a specific form to filter events. Only events from that form will trigger the webhook. Leave the filter empty to receive events for all forms in your workspace.

What happens if my server is down?

The delivery will fail and be logged with the error. Uplup does not retry failed deliveries. Monitor your delivery logs regularly to catch any issues.