Skip to main content

What are Webhooks?

Webhooks send HTTP POST requests to your specified URL when someone submits your form. Use Cases:
  • Custom CRM integration
  • Trigger automation workflows
  • Update external databases
  • Send data to your own server
  • Real-time data sync
  • Trigger third-party services
  • Custom notification systems

How Webhooks Work

  1. User submits form → TopFormBuilder captures submission
  2. Webhook triggers → Sends POST request to your URL
  3. Your server receives → Processes submission data
  4. Response returned → Success or failure status
Real-time: Webhooks fire immediately after form submission (within seconds)

Setting Up Webhooks

Step 1: Prepare Your Endpoint

Before adding webhook in TopFormBuilder, prepare your receiving endpoint: Requirements:
  • Public HTTPS URL (SSL required)
  • Accepts POST requests
  • Returns HTTP 200 status on success
  • Responds within 30 seconds (timeout)
Example URL:
https://yourdomain.com/api/webhooks/topformbuilder

Step 2: Add Webhook Integration

  1. Open your form in Form Builder
  2. Go to Settings tab
  3. Click Integrations section
  4. Click “Add Integration”
  5. Select “Webhook”

Step 3: Configure Webhook

Webhook URL (required)
  • Enter your endpoint URL
  • Must start with https://
  • Example: https://api.yoursite.com/webhooks/forms
Custom Headers (optional)
  • Add authentication headers
  • Example: Authorization: Bearer YOUR_TOKEN
  • Format: Header-Name: Value (one per line)
Secret Key (recommended)
  • Shared secret for verification
  • Used to sign requests
  • Verify webhook authenticity
  • Generate secure random string
Retry Failed Requests
  • ☑ Auto-retry on failure (recommended)
  • Retries up to 3 times
  • Exponential backoff (1s, 5s, 15s delays)
Timeout
  • Default: 30 seconds
  • Maximum wait for response
  • Fails if no response within timeout

Step 4: Test Webhook

  1. Click “Test Webhook” button
  2. Sample data sent to your URL
  3. Check your server receives data
  4. Verify response status 200
  5. Review payload format
If test fails:
  • Check URL is correct and accessible
  • Verify server accepts POST requests
  • Check firewall/security settings
  • Review server logs for errors

Step 5: Save & Activate

  1. Click “Save Integration”
  2. Toggle “Active” to ON
  3. Webhook is now live!

Webhook Payload

Request Format

Method: POST Content-Type: application/json Body: JSON object with submission data

Payload Structure

{
  "event": "form.submission.created",
  "form_id": 123,
  "form_name": "Customer Feedback Survey",
  "form_slug": "customer-feedback",
  "submission_id": 456,
  "submitted_at": "2024-03-15T10:30:00Z",
  "ip_address": "192.168.1.1",
  "user_agent": "Mozilla/5.0...",
  "device_type": "desktop",
  "time_taken": 125,
  "answers": [
    {
      "block_id": 1,
      "question": "What's your name?",
      "answer": "John Doe",
      "type": "short_text"
    },
    {
      "block_id": 2,
      "question": "Email address?",
      "answer": "[email protected]",
      "type": "email"
    },
    {
      "block_id": 3,
      "question": "How would you rate us?",
      "answer": 5,
      "type": "rating"
    }
  ],
  "metadata": {
    "location": {
      "country": "US",
      "city": "New York"
    },
    "referrer": "https://google.com",
    "utm_source": "email",
    "utm_campaign": "spring2024"
  }
}

Headers Sent

Standard Headers:
POST /webhook HTTP/1.1
Host: yourdomain.com
Content-Type: application/json
Content-Length: 1234
User-Agent: TopFormBuilder-Webhook/1.0
X-TFB-Event: form.submission.created
X-TFB-Signature: sha256=abc123...
X-TFB-Delivery: uuid-goes-here
Custom Headers: Any headers you configured are included

Verifying Webhooks

Verify webhook authenticity using HMAC signature: Signature Header: X-TFB-Signature Format: sha256=<signature> Verification Steps:
  1. Extract signature from header
  2. Compute HMAC of request body using your secret key
  3. Compare signatures
  4. Accept request if signatures match
Example (Node.js):
const crypto = require('crypto');

function verifyWebhook(request, secret) {
  const signature = request.headers['x-tfb-signature'];
  const body = JSON.stringify(request.body);

  const expectedSignature = 'sha256=' +
    crypto
      .createHmac('sha256', secret)
      .update(body)
      .digest('hex');

  return signature === expectedSignature;
}
Example (PHP):
function verifyWebhook($request, $secret) {
    $signature = $request->header('X-TFB-Signature');
    $body = $request->getContent();

    $expectedSignature = 'sha256=' .
        hash_hmac('sha256', $body, $secret);

    return hash_equals($signature, $expectedSignature);
}
Example (Python):
import hmac
import hashlib

def verify_webhook(request, secret):
    signature = request.headers.get('X-TFB-Signature')
    body = request.get_data()

    expected_signature = 'sha256=' + hmac.new(
        secret.encode(),
        body,
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(signature, expected_signature)

Handling Webhooks

Responding to Webhooks

Success Response:
HTTP/1.1 200 OK
Content-Type: application/json

{
  "success": true,
  "message": "Webhook received"
}
Failure Response:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
  "success": false,
  "error": "Database connection failed"
}
Best Practices:
  • Return 200 status immediately
  • Process webhook asynchronously (queue/background job)
  • Don’t make webhook wait for long operations
  • Log webhook data for debugging

Processing Submissions

Example Processing Flow:
  1. Receive webhook → Validate signature
  2. Parse JSON → Extract submission data
  3. Queue job → Add to background queue
  4. Return 200 → Acknowledge receipt quickly
  5. Process async → Handle data in background

Retry Logic

Automatic Retries:
  • Retry 1: After 1 second
  • Retry 2: After 5 seconds
  • Retry 3: After 15 seconds
  • Max retries: 3 attempts
Retries Triggered When:
  • HTTP status code ≠ 200
  • Connection timeout (30s)
  • Connection refused
  • SSL errors
Retries Not Triggered When:
  • 200 status returned (even if response body has errors)
  • 400-499 client errors (invalid request)
Disable Retries:
  • Uncheck “Retry Failed Requests” in settings
  • Webhook only fires once

Webhook Events

Available Events

form.submission.created (default)
  • New form submission received
  • Most common event
  • Includes all submission data
form.submission.updated (coming soon)
  • Submission edited/updated
  • Includes updated data
form.submission.deleted (coming soon)
  • Submission deleted
  • Includes submission ID only

Monitoring Webhooks

Webhook Logs

View webhook delivery history:
  1. Go to Form → Integrations
  2. Click “View Logs” on webhook integration
  3. See all webhook deliveries
Log Information:
  • Delivery ID
  • Timestamp
  • Status (success/failure)
  • HTTP status code
  • Response body
  • Response time
  • Retry attempts
Filtering Logs:
  • Last 24 hours
  • Last 7 days
  • Last 30 days
  • All time

Retry Failed Webhooks

Manually retry failed deliveries:
  1. Go to webhook logs
  2. Find failed delivery
  3. Click “Retry” button
  4. Webhook resent immediately
  5. Check new delivery status

Common Integrations

Zapier Alternative

Use webhooks to connect with thousands of apps:
  1. Create Zapier Zap with “Webhooks by Zapier” trigger
  2. Copy webhook URL from Zapier
  3. Paste into TopFormBuilder webhook integration
  4. Connect to any Zapier-supported app

Make (Integromat) Alternative

Similar to Zapier:
  1. Create Make scenario with “Webhooks” module
  2. Copy webhook URL
  3. Add to TopFormBuilder
  4. Build automation workflow

Custom CRM

Send leads directly to your CRM:
// Example: Your server receives webhook
app.post('/webhooks/topformbuilder', (req, res) => {
  const submission = req.body;

  // Add lead to CRM
  await crm.leads.create({
    name: submission.answers.find(a => a.type === 'short_text').answer,
    email: submission.answers.find(a => a.type === 'email').answer,
    source: 'TopFormBuilder',
    form_name: submission.form_name
  });

  res.status(200).json({ success: true });
});

Database Integration

Store submissions in your database:
# Example: Flask app receives webhook
@app.route('/webhooks/forms', methods=['POST'])
def handle_webhook():
    data = request.json

    # Insert into database
    db.submissions.insert({
        'form_id': data['form_id'],
        'submission_id': data['submission_id'],
        'answers': data['answers'],
        'submitted_at': data['submitted_at']
    })

    return {'success': True}, 200

Security Best Practices

Do:
  • Use HTTPS only (never HTTP)
  • Verify webhook signatures
  • Whitelist TopFormBuilder IPs (optional)
  • Rate limit webhook endpoint
  • Log all webhook deliveries
  • Use secrets for authentication
Don’t:
  • Expose webhook URL publicly
  • Skip signature verification
  • Process webhooks synchronously (timeout risk)
  • Return sensitive data in response
  • Trust webhook data without validation

Troubleshooting

”Webhook delivery failed”

Problem: Webhook not reaching your server Solutions:
  • Verify URL is correct and accessible
  • Check server is running
  • Ensure HTTPS (not HTTP)
  • Check firewall allows incoming requests
  • Review server logs for errors
  • Test with curl/Postman

”Timeout error”

Problem: Server not responding within 30 seconds Solutions:
  • Return 200 immediately
  • Process webhook asynchronously
  • Optimize server performance
  • Increase server resources

”SSL certificate error”

Problem: Invalid SSL certificate Solutions:
  • Ensure valid SSL certificate installed
  • Check certificate not expired
  • Verify domain matches certificate
  • Use trusted CA (not self-signed)

“Signature verification failed”

Problem: Signature doesn’t match Solutions:
  • Check secret key is correct
  • Verify using raw request body (not parsed JSON)
  • Check HMAC algorithm (SHA256)
  • Ensure UTF-8 encoding

Next Steps


Need help? Contact [email protected]