Help center

Webhooks

Webhooks allow you to receive form submission data in real-time by sending HTTP POST requests to your server or any third-party service.

Overview

When a form is submitted, Axiforms sends a standardized JSON payload to your configured webhook URL. This enables you to:

  • Process form data in your own backend
  • Trigger custom workflows and automations
  • Integrate with any service that accepts webhooks
  • Build custom integrations

Setting Up Webhooks

  1. Navigate to your form's SettingsIntegrations
  2. Click on Webhooks
  3. Enable the integration
  4. Enter your webhook URL (e.g., https://your-server.com/webhook)
  5. Optionally configure:
    • Secret Key: For HMAC signature verification
    • Custom Headers: Additional HTTP headers
    • Timeout: Request timeout (default: 30 seconds)
    • Retries: Number of retry attempts (default: 3)
  6. Click Create Integration

Webhook Payload

All webhooks receive a standardized JSON payload:

{
  "event": "form.submitted",
  "projectId": "clx123...",
  "responseId": "clx456...",
  "submittedAt": "2024-01-15T10:30:00.000Z",
  "metadata": {
    "ip": "192.168.1.1",
    "userAgent": "Mozilla/5.0...",
    "referer": "https://example.com"
  },
  "responses": [
    {
      "blockId": "block_123",
      "blockType": "text",
      "label": "Full Name",
      "value": "John Doe"
    },
    {
      "blockId": "block_456",
      "blockType": "email",
      "label": "Email Address",
      "value": "john@example.com"
    }
  ],
  "form": {
    "id": "clx123...",
    "name": "Contact Form",
    "slug": "contact-form"
  }
}

Note: All integrations (Webhooks, Zapier, n8n) receive the same standardized payload format.

Payload Fields

FieldTypeDescription
eventstringAlways "form.submitted"
projectIdstringUnique identifier for the form
responseIdstringUnique identifier for this submission
submittedAtstringISO 8601 timestamp of submission
metadataobjectSubmission metadata (IP, user agent, etc.)
responsesarrayArray of field responses
formobjectForm information (id, name, slug)

Response Object

Each item in the responses array contains:

FieldTypeDescription
blockIdstringUnique identifier for the form field
blockTypestringType of form field (e.g., text, email, select)
labelstringField label (if available)
valueanyField value (type depends on field type)

Security: HMAC Signatures

To verify that webhook requests are coming from Axiforms, you can enable HMAC signature verification:

  1. Set a Secret Key in your webhook configuration
  2. Axiforms will include an X-Webhook-Signature header in all requests
  3. Verify the signature on your server

Signature Format

X-Webhook-Signature: sha256=<hex_signature>

Verification Example (Node.js)

const crypto = require("crypto");

function verifySignature(payload, signature, secret) {
  const hmac = crypto.createHmac("sha256", secret);
  const computedSignature = hmac.update(JSON.stringify(payload)).digest("hex");
  const expectedSignature = signature.replace("sha256=", "");

  return crypto.timingSafeEqual(
    Buffer.from(computedSignature),
    Buffer.from(expectedSignature)
  );
}

// In your webhook handler
app.post("/webhook", express.json(), (req, res) => {
  const signature = req.headers["x-webhook-signature"];
  const secret = process.env.WEBHOOK_SECRET;

  if (!verifySignature(req.body, signature, secret)) {
    return res.status(401).send("Invalid signature");
  }

  // Process webhook...
  res.status(200).send("OK");
});

Verification Example (Python)

import hmac
import hashlib

def verify_signature(payload, signature, secret):
    computed = hmac.new(
        secret.encode(),
        json.dumps(payload).encode(),
        hashlib.sha256
    ).hexdigest()
    expected = signature.replace('sha256=', '')
    return hmac.compare_digest(computed, expected)

# In your webhook handler
@app.route('/webhook', methods=['POST'])
def webhook():
    signature = request.headers.get('X-Webhook-Signature')
    secret = os.environ['WEBHOOK_SECRET']

    if not verify_signature(request.json, signature, secret):
        return 'Invalid signature', 401

    # Process webhook...
    return 'OK', 200

Custom Headers

You can add custom HTTP headers to webhook requests:

{
  "Authorization": "Bearer your-token",
  "X-Custom-Header": "custom-value"
}

These headers will be included in every webhook request.

Retry Logic

If a webhook request fails (non-2xx status code or timeout), Axiforms will automatically retry:

  • Default retries: 3 attempts
  • Backoff: Exponential backoff (1s, 2s, 4s)
  • Timeout: 30 seconds per request (configurable)

Webhooks are retried asynchronously and won't block form submissions.

Testing Webhooks

Use the Test Webhook button in the integration settings to send a test payload:

{
  "event": "form_submission_test",
  "id": "test_response_id_123",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "form": {
    "id": "your-project-id",
    "name": "Test Form",
    "slug": "test-form"
  },
  "metadata": {
    "ip": "127.0.0.1",
    "userAgent": "Test Agent",
    "country": "US",
    "city": "Testville"
  },
  "responses": [
    {
      "blockId": "test_field_1",
      "label": "Name",
      "type": "text",
      "value": "John Doe"
    },
    {
      "blockId": "test_field_2",
      "label": "Email",
      "type": "email",
      "value": "john.doe@example.com"
    }
  ]
}

Best Practices

  1. Always verify signatures when processing sensitive data
  2. Handle timeouts gracefully - Axiforms retries automatically, but your server should respond quickly
  3. Idempotency - Design your webhook handler to handle duplicate submissions (use responseId)
  4. Error handling - Return appropriate HTTP status codes:
    • 200-299: Success
    • 400-499: Client error (won't retry)
    • 500+: Server error (will retry)
  5. Logging - Log all webhook requests for debugging and auditing

Troubleshooting

Webhook not receiving data

  • Check that the webhook URL is accessible from the internet
  • Verify the URL is correct and uses https://
  • Check your server logs for incoming requests
  • Use the Test Webhook feature to verify connectivity

Signature verification failing

  • Ensure the secret key matches exactly (no extra spaces)
  • Verify you're using the raw request body (not parsed JSON) for signature calculation
  • Check that you're comparing signatures securely (use timingSafeEqual or compare_digest)

Timeout errors

  • Increase the timeout in webhook settings (max 60 seconds)
  • Optimize your webhook handler to respond quickly
  • Consider processing asynchronously and returning immediately