Webhook Connector

The webhook connector sends the full SubmissionEnvelope as a JSON POST (or PUT/PATCH) to any HTTP endpoint.

Config

Field Type Required Default Description
url string Yes Destination URL (must be valid)
method string No "POST" POST, PUT, or PATCH
headers Record<string, string> No {} Custom headers sent with every request

Behavior

  1. The connector sends an HTTP request to config.url using config.method
  2. Content-Type: application/json is always set
  3. Any custom config.headers are merged in (can override defaults)
  4. The request body is the full SubmissionEnvelope as JSON
  5. A non-2xx response is treated as a failure and triggers a retry
Response Truncation

Successful responses are truncated to 5,000 characters for logging purposes. This does not affect delivery.

Use Cases

Slack Incoming Webhook

Slack webhooks expect a specific payload format. Use a middleware service (like Zapier or a small Worker) to transform the SubmissionEnvelope into Slack's block format, or point the webhook at a custom backend that handles the transformation.

curl -X POST https://api.formdata.dev/v1/admin/forms/FORM_ID/destinations \
  -H "Content-Type: application/json" \
  -H "x-tenant-key: sk_live_abc123..." \
  -d '{
    "type": "webhook",
    "config": {
      "url": "https://your-api.example.com/formdata-to-slack",
      "method": "POST",
      "headers": {
        "X-Source": "formdata.dev"
      }
    },
    "isEnabled": true
  }'

Discord Webhook

Similar to Slack, Discord webhooks have their own payload format. Point at a transformer endpoint or use a service like Zapier:

curl -X POST https://api.formdata.dev/v1/admin/forms/FORM_ID/destinations \
  -H "Content-Type: application/json" \
  -H "x-tenant-key: sk_live_abc123..." \
  -d '{
    "type": "webhook",
    "config": {
      "url": "https://your-api.example.com/formdata-to-discord",
      "method": "POST"
    },
    "isEnabled": true
  }'

Zapier Catch Hook

Zapier's "Webhooks by Zapier" trigger accepts any JSON payload. Point the webhook URL directly at your Zapier catch hook:

curl -X POST https://api.formdata.dev/v1/admin/forms/FORM_ID/destinations \
  -H "Content-Type: application/json" \
  -H "x-tenant-key: sk_live_abc123..." \
  -d '{
    "type": "webhook",
    "config": {
      "url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/",
      "method": "POST"
    },
    "isEnabled": true
  }'

Custom Backend

If you have your own API, receive submissions directly:

curl -X POST https://api.formdata.dev/v1/admin/forms/FORM_ID/destinations \
  -H "Content-Type: application/json" \
  -H "x-tenant-key: sk_live_abc123..." \
  -d '{
    "type": "webhook",
    "config": {
      "url": "https://api.yourapp.com/webhooks/formdata",
      "method": "POST",
      "headers": {
        "Authorization": "Bearer your-secret-token"
      }
    },
    "isEnabled": true
  }'

Step-by-Step: Webhook to Your Own API

  1. Create a form (if you have not already):
curl -X POST https://api.formdata.dev/v1/admin/forms \
  -H "Content-Type: application/json" \
  -H "x-tenant-key: sk_live_abc123..." \
  -d '{
    "name": "Feedback Form",
    "slug": "feedback"
  }'

Save the form.id from the response.

  1. Add a webhook destination using the form ID:
curl -X POST https://api.formdata.dev/v1/admin/forms/FORM_ID/destinations \
  -H "Content-Type: application/json" \
  -H "x-tenant-key: sk_live_abc123..." \
  -d '{
    "type": "webhook",
    "config": {
      "url": "https://api.yourapp.com/webhooks/formdata",
      "method": "POST",
      "headers": {
        "Authorization": "Bearer your-secret-token"
      }
    }
  }'
  1. Test with a submission:
curl -X POST https://api.formdata.dev/v1/f/pk_YOUR_PUBLIC_KEY \
  -H "Content-Type: application/json" \
  -d '{"name": "Test User", "email": "[email protected]"}'
  1. Verify — your endpoint should receive a JSON SubmissionEnvelope with the payload, submissionId, formName, and metadata fields.