Example

n8n — summarize new Tidy emails to Slack

A drop-in n8n workflow that listens for email.created Tidy events, summarizes the body with an LLM, and posts the summary to a Slack channel. Full signature verification included.

1. Import the workflow

Copy the JSON below into n8n via Import from URL / JSON. You'll need to configure credentials for Slack and your LLM provider.

{
  "name": "Tidy email to Slack",
  "nodes": [
    {
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "parameters": {
        "httpMethod": "POST",
        "path": "tidy-email-created",
        "responseCode": 204
      }
    },
    {
      "name": "Verify Tidy signature",
      "type": "n8n-nodes-base.code",
      "parameters": {
        "jsCode": "const crypto = require('crypto');\nconst sig = $input.first().json.headers['tidy-signature'];\nconst secret = $env.TIDY_WEBHOOK_SECRET;\nconst body = $input.first().json.bodyRaw;\nconst [, t, v1] = sig.match(/t=(\\d+),v1=([a-f0-9]+)/) || [];\nif (!t || !v1) throw new Error('bad sig');\nconst expected = crypto.createHmac('sha256', secret).update(`${t}.` + body).digest('hex');\nif (expected !== v1) throw new Error('sig mismatch');\nreturn $input.all();"
      }
    },
    {
      "name": "Summarize with LLM",
      "type": "n8n-nodes-base.openAi",
      "parameters": {
        "resource": "chat",
        "operation": "message",
        "model": "gpt-4o-mini",
        "messages": {
          "values": [
            {
              "role": "user",
              "content": "={{ \"Summarize in one line: \" + $json.data.subject + \"\\n\\n\" + $json.data.body_preview }}"
            }
          ]
        }
      }
    },
    {
      "name": "Post to Slack",
      "type": "n8n-nodes-base.slack",
      "parameters": {
        "resource": "message",
        "operation": "post",
        "channel": "#inbox",
        "text": "={{ \"New email: \" + $json.data.subject + \" — \" + $json('Summarize with LLM').item.json.message.content }}"
      }
    }
  ],
  "connections": {
    "Webhook": { "main": [[{ "node": "Verify Tidy signature", "type": "main", "index": 0 }]] },
    "Verify Tidy signature": { "main": [[{ "node": "Summarize with LLM", "type": "main", "index": 0 }]] },
    "Summarize with LLM": { "main": [[{ "node": "Post to Slack", "type": "main", "index": 0 }]] }
  }
}

2. Set the signing secret

In n8n, add an environment variable TIDY_WEBHOOK_SECRET with the signing secret you got when you created the subscription.

3. Subscribe Tidy to n8n

curl -X POST https://qa.tidy.engineering/api/v1/event_subscriptions \
  -H "Authorization: Bearer $TIDY_PAT" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://YOUR-N8N.example/webhook/tidy-email-created",
    "event_types": ["email.created"]
  }'

Verification logic

The "Verify Tidy signature" code node implements the same HMAC check documented on the webhooks page. It splits the Tidy-Signature header, reconstructs the MAC input, and throws if the signature doesn't match — aborting the workflow and returning a 401 to Tidy so the delivery retries.

Next steps

  • Extend to other event types: task.created, contact.merged, calendar.event_created.
  • Chain in a Tidy · tasks · create step via the HTTP Request node to auto-create follow-up tasks.
  • Swap Slack for Discord, Mattermost, Microsoft Teams.