LostChurn Docs
Integrations

n8n Webhook Integration

Use n8n's built-in Webhook node with LostChurn outbound webhooks for self-hosted workflow automation.

LostChurn sends real-time outbound webhooks that work directly with n8n's built-in Webhook node. No custom node installation required — just configure a Webhook trigger and start building workflows.

Prerequisites

  • An n8n instance (self-hosted or n8n Cloud)
  • A LostChurn account with webhook access (any paid plan)
  • A configured outbound webhook endpoint in Settings > Webhooks

Step-by-Step Setup

1. Create the n8n Webhook Trigger

  1. Open your n8n instance and create a New Workflow.
  2. Click the + button and search for Webhook.
  3. Add the Webhook node as your trigger.
  4. Set HTTP Method to POST.
  5. Set Path to something descriptive, e.g., lostchurn-events.
  6. Under Authentication, select None (we verify signatures in a separate step).
  7. Click Listen for Test Event to activate the webhook temporarily.

2. Register the Webhook in LostChurn

  1. Copy the Test URL from the n8n Webhook node (e.g., https://your-n8n.example.com/webhook-test/lostchurn-events).
  2. In your LostChurn dashboard, go to Settings > Webhooks.
  3. Click Add Endpoint.
  4. Paste the n8n webhook URL.
  5. Select the event types you want to receive.
  6. Click Create Endpoint.
  7. Copy the Signing Secret shown on creation — you will need it for signature verification.

The signing secret is only shown once at creation time. Copy it immediately and store it securely in n8n's credentials.

Add a Code node after the Webhook trigger to verify HMAC-SHA256 signatures:

  1. Add a Code node connected to the Webhook output.
  2. Set the language to JavaScript.
  3. Paste the following code:
const crypto = require('crypto');

// Store your signing secret in n8n Credentials or environment variables
const secret = 'whsec_your_signing_secret_here';
const signature = $input.first().headers['x-lostchurn-signature'];
const body = JSON.stringify($input.first().json);

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

if (signature !== expected) {
  throw new Error('Invalid LostChurn webhook signature — rejecting event');
}

// Signature valid — pass through
return $input.all();

For production workflows, store the signing secret as an n8n credential or environment variable rather than hardcoding it.

4. Filter by Event Type

Add an IF node or Switch node to route events by type:

Using a Switch node:

  1. Add a Switch node after the Code node.
  2. Set the Value to {{ $json.event }}.
  3. Add cases for each event type you want to handle:
    • recovery.succeeded
    • recovery.failed
    • payment.failed
    • campaign.completed

5. Test the Integration

  1. In n8n, ensure your Webhook node is in Listen for Test Event mode.
  2. In LostChurn, go to Settings > Webhooks and click Send Test Event on your endpoint.
  3. The test payload should appear in n8n.
  4. Once confirmed, switch the n8n Webhook to Production URL and activate the workflow.

Remember to update your LostChurn webhook endpoint URL from the test URL to the production URL before going live.

Example Workflow: Webhook to Slack Notification

This workflow receives a LostChurn recovery event and sends a formatted Slack notification.

Workflow JSON

Import this JSON into n8n via Workflow > Import from JSON:

{
  "name": "LostChurn Recovery to Slack",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "lostchurn-recovery",
        "responseMode": "onReceived",
        "responseCode": 200
      },
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [250, 300]
    },
    {
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.event }}",
              "operation": "equals",
              "value2": "recovery.succeeded"
            }
          ]
        }
      },
      "name": "Filter Recoveries",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [470, 300]
    },
    {
      "parameters": {
        "channel": "#revenue-recovered",
        "text": "={{ '💰 Payment Recovered!\\n' + 'Customer: ' + $json.data.customer_email + '\\n' + 'Amount: $' + ($json.data.amount / 100).toFixed(2) + '\\n' + 'Decline Code: ' + $json.data.decline_code + '\\n' + 'Retry Attempts: ' + $json.data.retry_count }}",
        "otherOptions": {}
      },
      "name": "Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2,
      "position": [690, 280]
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [{ "node": "Filter Recoveries", "type": "main", "index": 0 }]
      ]
    },
    "Filter Recoveries": {
      "main": [
        [{ "node": "Slack", "type": "main", "index": 0 }],
        []
      ]
    }
  }
}

How It Works

  1. Webhook node receives the LostChurn event payload via POST.
  2. Filter Recoveries checks if the event type is recovery.succeeded.
  3. Slack node sends a formatted message to #revenue-recovered with the recovery details.

Webhook Payload Format

All LostChurn outbound webhooks follow this structure:

{
  "event": "recovery.succeeded",
  "merchant_id": "550e8400-e29b-41d4-a716-446655440000",
  "payment_event_id": "660e8400-e29b-41d4-a716-446655440001",
  "timestamp": "2026-03-13T10:30:00Z",
  "data": {
    "recovery_id": "rec_abc123",
    "customer_email": "jane@example.com",
    "customer_name": "Jane Doe",
    "amount": 4999,
    "currency": "usd",
    "decline_code": "insufficient_funds",
    "retry_count": 2,
    "recovered_at": "2026-03-13T10:30:00Z"
  }
}

Headers

HeaderDescription
X-LostChurn-SignatureHMAC-SHA256 hex digest of the request body
X-LostChurn-EventEvent type (e.g., recovery.succeeded)
Content-Typeapplication/json
User-AgentLostChurn-Webhook/1.0

Available Event Types

EventDescription
payment_failedA payment charge was declined
retry_startedA retry attempt has been initiated
retry_succeededA retry attempt succeeded
retry_failedA retry attempt was declined
payment_recoveredA payment has been fully recovered
dunning_startedA dunning campaign has begun
terminalRecovery exhausted — all attempts failed

Common Workflow Patterns

High-Value Recovery Alert

Webhook → IF (amount > 10000) → Slack / Email / PagerDuty

Failed Payment to CRM

Webhook → Filter (payment_failed) → HTTP Request (HubSpot API) → Update Contact

Daily Recovery Digest

Schedule Trigger (daily) → HTTP Request (LostChurn API) → Aggregate → Email Summary

Escalation on Terminal

Webhook → Filter (terminal) → Create Zendesk Ticket → Assign to CS Team

Troubleshooting

Webhook not receiving events

  • Ensure n8n is publicly accessible (not behind localhost without a tunnel).
  • Verify the workflow is Active (toggle in the top-right corner).
  • Check LostChurn webhook delivery logs at Settings > Webhooks > Deliveries.
  • If using n8n Cloud, ensure you are using the Production URL, not the Test URL.

Signature verification failing

  • Confirm the signing secret matches exactly (no trailing whitespace).
  • Ensure the Code node receives the raw JSON body, not a transformed version.
  • Check that the x-lostchurn-signature header is accessible in the Webhook node output.

Events arriving but workflow not executing

  • Verify the Webhook node's HTTP method is set to POST.
  • Check the IF/Switch node conditions match the event types you expect.
  • Look at the n8n execution log for errors in individual nodes.

Next Steps

On this page