--- title: Webhooks description: Send real-time notifications to external services --- ## What are webhooks Webhooks let you send HTTP requests to external services from within workflows. Use them to: - Notify your CRM when workflows complete - Update external databases with contact actions - Trigger third-party automations - Sync data across systems - Track workflow progress in analytics tools ## Using webhooks in workflows Add a **Webhook** step to any workflow: 1. Go to **Workflows** 2. Create or edit a workflow 3. Add a **Webhook** step 4. Configure the HTTP request 5. Connect to other steps ### Basic webhook configuration ```json { "type": "WEBHOOK", "config": { "url": "https://your-api.com/webhook", "method": "POST", "headers": { "Content-Type": "application/json", "Authorization": "Bearer your_api_token" }, "body": { "email": "{{email}}", "event": "workflow_completed", "contactId": "{{id}}" } } } ``` ### Supported HTTP methods - **POST** — Most common, sends data to endpoint - **PUT** — Update existing resource - **PATCH** — Partial update - **GET** — Retrieve data (rarely used in workflows) - **DELETE** — Remove resource ## Using contact variables Access contact data in your webhook using template variables: ```json { "url": "https://crm.example.com/contacts", "method": "POST", "body": { "email": "{{email}}", "firstName": "{{data.firstName}}", "lastName": "{{data.lastName}}", "plan": "{{data.plan}}", "workflowName": "{{workflowName}}", "completedAt": "{{now}}" } } ``` Available variables: - `{{email}}` — Contact email - `{{id}}` — Contact ID - `{{data.fieldName}}` — Any custom data field - `{{workflowName}}` — Current workflow name - `{{now}}` — Current timestamp ## Common use cases ### Notify Slack ```json { "url": "https://hooks.slack.com/services/YOUR/WEBHOOK/URL", "method": "POST", "body": { "text": "New user completed onboarding: {{email}}" } } ``` ### Update CRM ```json { "url": "https://api.crm.com/contacts/{{data.crmId}}", "method": "PATCH", "headers": { "Authorization": "Bearer crm_api_token" }, "body": { "onboardingCompleted": true, "lastEngaged": "{{now}}" } } ``` ### Track analytics ```json { "url": "https://analytics.example.com/events", "method": "POST", "headers": { "X-API-Key": "analytics_key" }, "body": { "event": "workflow_milestone", "userId": "{{email}}", "properties": { "workflow": "{{workflowName}}", "step": "purchase_completed" } } } ``` ### Trigger Zapier ```json { "url": "https://hooks.zapier.com/hooks/catch/YOUR_WEBHOOK_ID/", "method": "POST", "body": { "email": "{{email}}", "firstName": "{{data.firstName}}", "event": "trial_ended" } } ``` ## Error handling ### Webhook failures If a webhook request fails: - Workflow continues to next step - Error is logged in workflow execution - Contact is not blocked Check workflow execution logs to see webhook errors: ```bash curl -X GET {{API_URL}}/workflows/workflow_id/executions \ -H "Authorization: Bearer sk_your_secret_key" ``` ### Timeouts Webhooks timeout after 30 seconds. If your endpoint takes longer: - Use async processing on your end - Return 202 Accepted immediately - Process in background job ### Retry logic Webhooks are **not automatically retried**. If you need guaranteed delivery: - Implement retry logic in your endpoint - Use a message queue (SQS, RabbitMQ) - Track webhook status in your database ## Receiving email event webhooks Plunk tracks email events automatically (opens, clicks, bounces). Access them via: ### Events API ```bash curl -X GET "{{API_URL}}/events?contactId=contact_id" \ -H "Authorization: Bearer sk_your_secret_key" ``` Returns email events: ```json { "events": [ { "name": "email.opened", "data": { "emailId": "...", "timestamp": "..." } }, { "name": "email.clicked", "data": { "emailId": "...", "url": "...", "timestamp": "..." } } ] } ``` ### Trigger workflows on email events Create a workflow triggered by email events: ```json { "triggerType": "EVENT", "triggerConfig": { "eventName": "email.clicked" } } ``` Then use a webhook step to forward to your system. ## Security best practices **Use HTTPS only** — Never send sensitive data over HTTP. **Authenticate requests** — Include API tokens in headers: ```json { "headers": { "Authorization": "Bearer your_secret_token" } } ``` **Validate on receiving end** — Don't trust webhook data blindly. Verify it matches your expectations. **Don't expose secrets** — Store API tokens as environment variables, not in workflow config. **Rate limit your endpoint** — Protect against webhook floods. ## Testing webhooks ### Use webhook.site For testing, use [webhook.site](https://webhook.site): 1. Go to webhook.site 2. Copy your unique URL 3. Use it in your workflow webhook step 4. Trigger the workflow 5. See the request in webhook.site ### Test with ngrok For local development: ```bash ngrok http 3000 ``` Use the ngrok URL in your webhook configuration. Requests will tunnel to your local server. ## What's next - [Build workflows](/guides/workflows) with webhook steps - [Track events](/guides/events) to trigger webhooks - [Monitor analytics](/guides/analytics) for webhook success rates