{"title":"Webhook Automation Guide","slug":"webhook-automation","category":"guides","summary":"","audience":["human"],"tags":[],"word_count":251,"read_minutes":1,"llm_context":"Practical patterns for using Synapse webhooks to automate workflows. Covers logging, summarization, external tool integration, sync to note-taking apps, and monitoring. Events: memory.created, memory.updated, memory.deleted, memory.verified, memory.unverified, task.updated, chat.message_sent.","lang":"en","translated":true,"requested_lang":"en","content_markdown":"# Webhook Automation Guide\n\nPractical patterns for automating workflows with Synapse webhooks.\n\n## Pattern 1: Memory Log\n\nLog every new memory to a file or external service.\n\n### Setup\n\n```python\nfrom flask import Flask, request, jsonify\nimport hashlib, hmac\n\napp = Flask(__name__)\nWEBHOOK_SECRET = 'your-webhook-secret'\n\n@app.route('/webhook', methods=['POST'])\ndef webhook():\n    # Verify signature\n    sig = request.headers.get('X-Synapse-Signature', '')\n    expected = 'sha256=' + hmac.new(WEBHOOK_SECRET.encode(), request.get_data(), hashlib.sha256).hexdigest()\n    if not hmac.compare_digest(sig, expected):\n        return jsonify({'error': 'invalid signature'}), 401\n\n    event = request.headers.get('X-Synapse-Event')\n    if event == 'memory.created':\n        data = request.get_json()\n        with open('memory-log.txt', 'a') as f:\n            f.write(f\"{data['event']}: {data['data']['key']} = {data['data']['content'][:100]}\\n\")\n        return jsonify({'status': 'ok'}), 200\n    return jsonify({'status': 'ignored'}), 200\n```\n\n### Explanation\n\nThe handler listens for `memory.created` events and logs each new memory's key and a content preview to a file. This is useful for auditing, debugging, or creating a secondary backup of important memories.\n\n## Pattern 2: Memory Summary\n\nSummarize new memories using an LLM and store the summary.\n\n### Setup\n\n```python\nfrom flask import Flask, request, jsonify\nimport hashlib, hmac\n\napp = Flask(__name__)\nWEBHOOK_SECRET = 'your-webhook-secret'\n\n@app.route('/webhook', methods=['POST'])\ndef webhook():\n    sig = request.headers.get('X-Synapse-Signature', '')\n    expected = 'sha256=' + hmac.new(WEBHOOK_SECRET.encode(), request.get_data(), hashlib.sha256).hexdigest()\n    if not hmac.compare_digest(sig, expected):\n        return jsonify({'error': 'invalid signature'}), 401\n\n    event = request.headers.get('X-Synapse-Event')\n    if event in ('memory.created', 'memory.updated'):\n        data = request.get_json()\n        content = data['data']['content']\n        # Send to your LLM for summarization\n        summary = summarize_with_llm(content)  # your function\n        store_summary(data['data']['key'], summary)\n        return jsonify({'status': 'summarized'}), 200\n    return jsonify({'status': 'ignored'}), 200\n```\n\n### Explanation\n\nThis pattern captures both `memory.created` and `memory.updated` events, sends the content to an LLM for summarization, and stores the result. Useful for maintaining a condensed knowledge base.\n\n## Pattern 3: Sync to Note-Taking App\n\nForward new memories to Notion, Obsidian, or similar tools.\n\n### Setup\n\n```python\nfrom flask import Flask, request, jsonify\nimport hashlib, hmac, requests\n\napp = Flask(__name__)\nWEBHOOK_SECRET = 'your-webhook-secret'\nNOTION_API_KEY = 'your-notion-key'\nNOTION_DATABASE_ID = 'your-database-id'\n\n@app.route('/webhook', methods=['POST'])\ndef webhook():\n    sig = request.headers.get('X-Synapse-Signature', '')\n    expected = 'sha256=' + hmac.new(WEBHOOK_SECRET.encode(), request.get_data(), hashlib.sha256).hexdigest()\n    if not hmac.compare_digest(sig, expected):\n        return jsonify({'error': 'invalid signature'}), 401\n\n    event = request.headers.get('X-Synapse-Event')\n    if event == 'memory.created':\n        data = request.get_json()\n        # Create Notion page\n        requests.post('https://api.notion.com/v1/pages', headers={\n            'Authorization': f'Bearer {NOTION_API_KEY}',\n            'Content-Type': 'application/json',\n            'Notion-Version': '2022-06-28',\n        }, json={\n            'parent': {'database_id': NOTION_DATABASE_ID},\n            'properties': {\n                'Title': {'title': [{'text': {'content': data['data']['key']}}]},\n                'Content': {'rich_text': [{'text': {'content': data['data']['content'][:2000]}}]},\n                'Category': {'select': {'name': data['data'].get('category', 'note')}},\n            },\n        })\n        return jsonify({'status': 'synced'}), 200\n    return jsonify({'status': 'ignored'}), 200\n```\n\n### Explanation\n\nThis pattern forwards each new memory to a Notion database, preserving the key as the title, content as a text property, and category as a select field. Adapt the API call for Obsidian, Logseq, or other tools.\n\n## Pattern 4: Monitoring & Alerting\n\nGet notified when memories are deleted or when tasks fail.\n\n### Setup\n\n```python\nfrom flask import Flask, request, jsonify\nimport hashlib, hmac\n\napp = Flask(__name__)\nWEBHOOK_SECRET = 'your-webhook-secret'\n\n@app.route('/webhook', methods=['POST'])\ndef webhook():\n    sig = request.headers.get('X-Synapse-Signature', '')\n    expected = 'sha256=' + hmac.new(WEBHOOK_SECRET.encode(), request.get_data(), hashlib.sha256).hexdigest()\n    if not hmac.compare_digest(sig, expected):\n        return jsonify({'error': 'invalid signature'}), 401\n\n    event = request.headers.get('X-Synapse-Event')\n    data = request.get_json()\n\n    if event == 'memory.deleted':\n        send_alert(f\"Memory deleted: {data['data']['key']}\")\n    elif event == 'task.updated':\n        task_data = data['data']\n        if task_data.get('status') == 'failed':\n            send_alert(f\"Task failed: {task_data.get('name', 'unknown')}\")\n\n    return jsonify({'status': 'ok'}), 200\n\ndef send_alert(message):\n    # Send to Slack, Discord, email, etc.\n    print(f'ALERT: {message}')\n```\n\n### Explanation\n\nThis pattern monitors for `memory.deleted` and `task.updated` events. When a memory is deleted or a task fails, it triggers an alert. Useful for monitoring and ensuring data integrity.\n\n## Pattern 5: Chat Message Relay\n\nForward chat messages to an external system for logging or analysis.\n\n### Setup\n\n```python\nfrom flask import Flask, request, jsonify\nimport hashlib, hmac\n\napp = Flask(__name__)\nWEBHOOK_SECRET = 'your-webhook-secret'\n\n@app.route('/webhook', methods=['POST'])\ndef webhook():\n    sig = request.headers.get('X-Synapse-Signature', '')\n    expected = 'sha256=' + hmac.new(WEBHOOK_SECRET.encode(), request.get_data(), hashlib.sha256).hexdigest()\n    if not hmac.compare_digest(sig, expected):\n        return jsonify({'error': 'invalid signature'}), 401\n\n    event = request.headers.get('X-Synapse-Event')\n    if event == 'chat.message_sent':\n        data = request.get_json()\n        # Process chat message\n        log_chat_message(data['data'])\n        return jsonify({'status': 'ok'}), 200\n    return jsonify({'status': 'ignored'}), 200\n```\n\n### Explanation\n\nThis pattern listens for `chat.message_sent` events and forwards them to an external logging or analysis system. Useful for conversation analytics, compliance logging, or integration with CRM systems.\n","content_html":"<h1>Webhook Automation Guide</h1>\n<p>Practical patterns for automating workflows with Synapse webhooks.</p>\n<h2>Pattern 1: Memory Log</h2>\n<p>Log every new memory to a file or external service.</p>\n<h3>Setup</h3>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-keyword\">from</span> flask <span class=\"hljs-keyword\">import</span> Flask, request, jsonify\n<span class=\"hljs-keyword\">import</span> hashlib, hmac\n\napp = Flask(__name__)\nWEBHOOK_SECRET = <span class=\"hljs-string\">&#x27;your-webhook-secret&#x27;</span>\n\n<span class=\"hljs-meta\">@app.route(<span class=\"hljs-params\"><span class=\"hljs-string\">&#x27;/webhook&#x27;</span>, methods=[<span class=\"hljs-string\">&#x27;POST&#x27;</span>]</span>)</span>\n<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">webhook</span>():\n    <span class=\"hljs-comment\"># Verify signature</span>\n    sig = request.headers.get(<span class=\"hljs-string\">&#x27;X-Synapse-Signature&#x27;</span>, <span class=\"hljs-string\">&#x27;&#x27;</span>)\n    expected = <span class=\"hljs-string\">&#x27;sha256=&#x27;</span> + hmac.new(WEBHOOK_SECRET.encode(), request.get_data(), hashlib.sha256).hexdigest()\n    <span class=\"hljs-keyword\">if</span> <span class=\"hljs-keyword\">not</span> hmac.compare_digest(sig, expected):\n        <span class=\"hljs-keyword\">return</span> jsonify({<span class=\"hljs-string\">&#x27;error&#x27;</span>: <span class=\"hljs-string\">&#x27;invalid signature&#x27;</span>}), <span class=\"hljs-number\">401</span>\n\n    event = request.headers.get(<span class=\"hljs-string\">&#x27;X-Synapse-Event&#x27;</span>)\n    <span class=\"hljs-keyword\">if</span> event == <span class=\"hljs-string\">&#x27;memory.created&#x27;</span>:\n        data = request.get_json()\n        <span class=\"hljs-keyword\">with</span> <span class=\"hljs-built_in\">open</span>(<span class=\"hljs-string\">&#x27;memory-log.txt&#x27;</span>, <span class=\"hljs-string\">&#x27;a&#x27;</span>) <span class=\"hljs-keyword\">as</span> f:\n            f.write(<span class=\"hljs-string\">f&quot;<span class=\"hljs-subst\">{data[<span class=\"hljs-string\">&#x27;event&#x27;</span>]}</span>: <span class=\"hljs-subst\">{data[<span class=\"hljs-string\">&#x27;data&#x27;</span>][<span class=\"hljs-string\">&#x27;key&#x27;</span>]}</span> = <span class=\"hljs-subst\">{data[<span class=\"hljs-string\">&#x27;data&#x27;</span>][<span class=\"hljs-string\">&#x27;content&#x27;</span>][:<span class=\"hljs-number\">100</span>]}</span>\\n&quot;</span>)\n        <span class=\"hljs-keyword\">return</span> jsonify({<span class=\"hljs-string\">&#x27;status&#x27;</span>: <span class=\"hljs-string\">&#x27;ok&#x27;</span>}), <span class=\"hljs-number\">200</span>\n    <span class=\"hljs-keyword\">return</span> jsonify({<span class=\"hljs-string\">&#x27;status&#x27;</span>: <span class=\"hljs-string\">&#x27;ignored&#x27;</span>}), <span class=\"hljs-number\">200</span></code></pre><h3>Explanation</h3>\n<p>The handler listens for <code>memory.created</code> events and logs each new memory&#39;s key and a content preview to a file. This is useful for auditing, debugging, or creating a secondary backup of important memories.</p>\n<h2>Pattern 2: Memory Summary</h2>\n<p>Summarize new memories using an LLM and store the summary.</p>\n<h3>Setup</h3>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-keyword\">from</span> flask <span class=\"hljs-keyword\">import</span> Flask, request, jsonify\n<span class=\"hljs-keyword\">import</span> hashlib, hmac\n\napp = Flask(__name__)\nWEBHOOK_SECRET = <span class=\"hljs-string\">&#x27;your-webhook-secret&#x27;</span>\n\n<span class=\"hljs-meta\">@app.route(<span class=\"hljs-params\"><span class=\"hljs-string\">&#x27;/webhook&#x27;</span>, methods=[<span class=\"hljs-string\">&#x27;POST&#x27;</span>]</span>)</span>\n<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">webhook</span>():\n    sig = request.headers.get(<span class=\"hljs-string\">&#x27;X-Synapse-Signature&#x27;</span>, <span class=\"hljs-string\">&#x27;&#x27;</span>)\n    expected = <span class=\"hljs-string\">&#x27;sha256=&#x27;</span> + hmac.new(WEBHOOK_SECRET.encode(), request.get_data(), hashlib.sha256).hexdigest()\n    <span class=\"hljs-keyword\">if</span> <span class=\"hljs-keyword\">not</span> hmac.compare_digest(sig, expected):\n        <span class=\"hljs-keyword\">return</span> jsonify({<span class=\"hljs-string\">&#x27;error&#x27;</span>: <span class=\"hljs-string\">&#x27;invalid signature&#x27;</span>}), <span class=\"hljs-number\">401</span>\n\n    event = request.headers.get(<span class=\"hljs-string\">&#x27;X-Synapse-Event&#x27;</span>)\n    <span class=\"hljs-keyword\">if</span> event <span class=\"hljs-keyword\">in</span> (<span class=\"hljs-string\">&#x27;memory.created&#x27;</span>, <span class=\"hljs-string\">&#x27;memory.updated&#x27;</span>):\n        data = request.get_json()\n        content = data[<span class=\"hljs-string\">&#x27;data&#x27;</span>][<span class=\"hljs-string\">&#x27;content&#x27;</span>]\n        <span class=\"hljs-comment\"># Send to your LLM for summarization</span>\n        summary = summarize_with_llm(content)  <span class=\"hljs-comment\"># your function</span>\n        store_summary(data[<span class=\"hljs-string\">&#x27;data&#x27;</span>][<span class=\"hljs-string\">&#x27;key&#x27;</span>], summary)\n        <span class=\"hljs-keyword\">return</span> jsonify({<span class=\"hljs-string\">&#x27;status&#x27;</span>: <span class=\"hljs-string\">&#x27;summarized&#x27;</span>}), <span class=\"hljs-number\">200</span>\n    <span class=\"hljs-keyword\">return</span> jsonify({<span class=\"hljs-string\">&#x27;status&#x27;</span>: <span class=\"hljs-string\">&#x27;ignored&#x27;</span>}), <span class=\"hljs-number\">200</span></code></pre><h3>Explanation</h3>\n<p>This pattern captures both <code>memory.created</code> and <code>memory.updated</code> events, sends the content to an LLM for summarization, and stores the result. Useful for maintaining a condensed knowledge base.</p>\n<h2>Pattern 3: Sync to Note-Taking App</h2>\n<p>Forward new memories to Notion, Obsidian, or similar tools.</p>\n<h3>Setup</h3>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-keyword\">from</span> flask <span class=\"hljs-keyword\">import</span> Flask, request, jsonify\n<span class=\"hljs-keyword\">import</span> hashlib, hmac, requests\n\napp = Flask(__name__)\nWEBHOOK_SECRET = <span class=\"hljs-string\">&#x27;your-webhook-secret&#x27;</span>\nNOTION_API_KEY = <span class=\"hljs-string\">&#x27;your-notion-key&#x27;</span>\nNOTION_DATABASE_ID = <span class=\"hljs-string\">&#x27;your-database-id&#x27;</span>\n\n<span class=\"hljs-meta\">@app.route(<span class=\"hljs-params\"><span class=\"hljs-string\">&#x27;/webhook&#x27;</span>, methods=[<span class=\"hljs-string\">&#x27;POST&#x27;</span>]</span>)</span>\n<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">webhook</span>():\n    sig = request.headers.get(<span class=\"hljs-string\">&#x27;X-Synapse-Signature&#x27;</span>, <span class=\"hljs-string\">&#x27;&#x27;</span>)\n    expected = <span class=\"hljs-string\">&#x27;sha256=&#x27;</span> + hmac.new(WEBHOOK_SECRET.encode(), request.get_data(), hashlib.sha256).hexdigest()\n    <span class=\"hljs-keyword\">if</span> <span class=\"hljs-keyword\">not</span> hmac.compare_digest(sig, expected):\n        <span class=\"hljs-keyword\">return</span> jsonify({<span class=\"hljs-string\">&#x27;error&#x27;</span>: <span class=\"hljs-string\">&#x27;invalid signature&#x27;</span>}), <span class=\"hljs-number\">401</span>\n\n    event = request.headers.get(<span class=\"hljs-string\">&#x27;X-Synapse-Event&#x27;</span>)\n    <span class=\"hljs-keyword\">if</span> event == <span class=\"hljs-string\">&#x27;memory.created&#x27;</span>:\n        data = request.get_json()\n        <span class=\"hljs-comment\"># Create Notion page</span>\n        requests.post(<span class=\"hljs-string\">&#x27;https://api.notion.com/v1/pages&#x27;</span>, headers={\n            <span class=\"hljs-string\">&#x27;Authorization&#x27;</span>: <span class=\"hljs-string\">f&#x27;Bearer <span class=\"hljs-subst\">{NOTION_API_KEY}</span>&#x27;</span>,\n            <span class=\"hljs-string\">&#x27;Content-Type&#x27;</span>: <span class=\"hljs-string\">&#x27;application/json&#x27;</span>,\n            <span class=\"hljs-string\">&#x27;Notion-Version&#x27;</span>: <span class=\"hljs-string\">&#x27;2022-06-28&#x27;</span>,\n        }, json={\n            <span class=\"hljs-string\">&#x27;parent&#x27;</span>: {<span class=\"hljs-string\">&#x27;database_id&#x27;</span>: NOTION_DATABASE_ID},\n            <span class=\"hljs-string\">&#x27;properties&#x27;</span>: {\n                <span class=\"hljs-string\">&#x27;Title&#x27;</span>: {<span class=\"hljs-string\">&#x27;title&#x27;</span>: [{<span class=\"hljs-string\">&#x27;text&#x27;</span>: {<span class=\"hljs-string\">&#x27;content&#x27;</span>: data[<span class=\"hljs-string\">&#x27;data&#x27;</span>][<span class=\"hljs-string\">&#x27;key&#x27;</span>]}}]},\n                <span class=\"hljs-string\">&#x27;Content&#x27;</span>: {<span class=\"hljs-string\">&#x27;rich_text&#x27;</span>: [{<span class=\"hljs-string\">&#x27;text&#x27;</span>: {<span class=\"hljs-string\">&#x27;content&#x27;</span>: data[<span class=\"hljs-string\">&#x27;data&#x27;</span>][<span class=\"hljs-string\">&#x27;content&#x27;</span>][:<span class=\"hljs-number\">2000</span>]}}]},\n                <span class=\"hljs-string\">&#x27;Category&#x27;</span>: {<span class=\"hljs-string\">&#x27;select&#x27;</span>: {<span class=\"hljs-string\">&#x27;name&#x27;</span>: data[<span class=\"hljs-string\">&#x27;data&#x27;</span>].get(<span class=\"hljs-string\">&#x27;category&#x27;</span>, <span class=\"hljs-string\">&#x27;note&#x27;</span>)}},\n            },\n        })\n        <span class=\"hljs-keyword\">return</span> jsonify({<span class=\"hljs-string\">&#x27;status&#x27;</span>: <span class=\"hljs-string\">&#x27;synced&#x27;</span>}), <span class=\"hljs-number\">200</span>\n    <span class=\"hljs-keyword\">return</span> jsonify({<span class=\"hljs-string\">&#x27;status&#x27;</span>: <span class=\"hljs-string\">&#x27;ignored&#x27;</span>}), <span class=\"hljs-number\">200</span></code></pre><h3>Explanation</h3>\n<p>This pattern forwards each new memory to a Notion database, preserving the key as the title, content as a text property, and category as a select field. Adapt the API call for Obsidian, Logseq, or other tools.</p>\n<h2>Pattern 4: Monitoring &amp; Alerting</h2>\n<p>Get notified when memories are deleted or when tasks fail.</p>\n<h3>Setup</h3>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-keyword\">from</span> flask <span class=\"hljs-keyword\">import</span> Flask, request, jsonify\n<span class=\"hljs-keyword\">import</span> hashlib, hmac\n\napp = Flask(__name__)\nWEBHOOK_SECRET = <span class=\"hljs-string\">&#x27;your-webhook-secret&#x27;</span>\n\n<span class=\"hljs-meta\">@app.route(<span class=\"hljs-params\"><span class=\"hljs-string\">&#x27;/webhook&#x27;</span>, methods=[<span class=\"hljs-string\">&#x27;POST&#x27;</span>]</span>)</span>\n<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">webhook</span>():\n    sig = request.headers.get(<span class=\"hljs-string\">&#x27;X-Synapse-Signature&#x27;</span>, <span class=\"hljs-string\">&#x27;&#x27;</span>)\n    expected = <span class=\"hljs-string\">&#x27;sha256=&#x27;</span> + hmac.new(WEBHOOK_SECRET.encode(), request.get_data(), hashlib.sha256).hexdigest()\n    <span class=\"hljs-keyword\">if</span> <span class=\"hljs-keyword\">not</span> hmac.compare_digest(sig, expected):\n        <span class=\"hljs-keyword\">return</span> jsonify({<span class=\"hljs-string\">&#x27;error&#x27;</span>: <span class=\"hljs-string\">&#x27;invalid signature&#x27;</span>}), <span class=\"hljs-number\">401</span>\n\n    event = request.headers.get(<span class=\"hljs-string\">&#x27;X-Synapse-Event&#x27;</span>)\n    data = request.get_json()\n\n    <span class=\"hljs-keyword\">if</span> event == <span class=\"hljs-string\">&#x27;memory.deleted&#x27;</span>:\n        send_alert(<span class=\"hljs-string\">f&quot;Memory deleted: <span class=\"hljs-subst\">{data[<span class=\"hljs-string\">&#x27;data&#x27;</span>][<span class=\"hljs-string\">&#x27;key&#x27;</span>]}</span>&quot;</span>)\n    <span class=\"hljs-keyword\">elif</span> event == <span class=\"hljs-string\">&#x27;task.updated&#x27;</span>:\n        task_data = data[<span class=\"hljs-string\">&#x27;data&#x27;</span>]\n        <span class=\"hljs-keyword\">if</span> task_data.get(<span class=\"hljs-string\">&#x27;status&#x27;</span>) == <span class=\"hljs-string\">&#x27;failed&#x27;</span>:\n            send_alert(<span class=\"hljs-string\">f&quot;Task failed: <span class=\"hljs-subst\">{task_data.get(<span class=\"hljs-string\">&#x27;name&#x27;</span>, <span class=\"hljs-string\">&#x27;unknown&#x27;</span>)}</span>&quot;</span>)\n\n    <span class=\"hljs-keyword\">return</span> jsonify({<span class=\"hljs-string\">&#x27;status&#x27;</span>: <span class=\"hljs-string\">&#x27;ok&#x27;</span>}), <span class=\"hljs-number\">200</span>\n\n<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">send_alert</span>(<span class=\"hljs-params\">message</span>):\n    <span class=\"hljs-comment\"># Send to Slack, Discord, email, etc.</span>\n    <span class=\"hljs-built_in\">print</span>(<span class=\"hljs-string\">f&#x27;ALERT: <span class=\"hljs-subst\">{message}</span>&#x27;</span>)</code></pre><h3>Explanation</h3>\n<p>This pattern monitors for <code>memory.deleted</code> and <code>task.updated</code> events. When a memory is deleted or a task fails, it triggers an alert. Useful for monitoring and ensuring data integrity.</p>\n<h2>Pattern 5: Chat Message Relay</h2>\n<p>Forward chat messages to an external system for logging or analysis.</p>\n<h3>Setup</h3>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-keyword\">from</span> flask <span class=\"hljs-keyword\">import</span> Flask, request, jsonify\n<span class=\"hljs-keyword\">import</span> hashlib, hmac\n\napp = Flask(__name__)\nWEBHOOK_SECRET = <span class=\"hljs-string\">&#x27;your-webhook-secret&#x27;</span>\n\n<span class=\"hljs-meta\">@app.route(<span class=\"hljs-params\"><span class=\"hljs-string\">&#x27;/webhook&#x27;</span>, methods=[<span class=\"hljs-string\">&#x27;POST&#x27;</span>]</span>)</span>\n<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">webhook</span>():\n    sig = request.headers.get(<span class=\"hljs-string\">&#x27;X-Synapse-Signature&#x27;</span>, <span class=\"hljs-string\">&#x27;&#x27;</span>)\n    expected = <span class=\"hljs-string\">&#x27;sha256=&#x27;</span> + hmac.new(WEBHOOK_SECRET.encode(), request.get_data(), hashlib.sha256).hexdigest()\n    <span class=\"hljs-keyword\">if</span> <span class=\"hljs-keyword\">not</span> hmac.compare_digest(sig, expected):\n        <span class=\"hljs-keyword\">return</span> jsonify({<span class=\"hljs-string\">&#x27;error&#x27;</span>: <span class=\"hljs-string\">&#x27;invalid signature&#x27;</span>}), <span class=\"hljs-number\">401</span>\n\n    event = request.headers.get(<span class=\"hljs-string\">&#x27;X-Synapse-Event&#x27;</span>)\n    <span class=\"hljs-keyword\">if</span> event == <span class=\"hljs-string\">&#x27;chat.message_sent&#x27;</span>:\n        data = request.get_json()\n        <span class=\"hljs-comment\"># Process chat message</span>\n        log_chat_message(data[<span class=\"hljs-string\">&#x27;data&#x27;</span>])\n        <span class=\"hljs-keyword\">return</span> jsonify({<span class=\"hljs-string\">&#x27;status&#x27;</span>: <span class=\"hljs-string\">&#x27;ok&#x27;</span>}), <span class=\"hljs-number\">200</span>\n    <span class=\"hljs-keyword\">return</span> jsonify({<span class=\"hljs-string\">&#x27;status&#x27;</span>: <span class=\"hljs-string\">&#x27;ignored&#x27;</span>}), <span class=\"hljs-number\">200</span></code></pre><h3>Explanation</h3>\n<p>This pattern listens for <code>chat.message_sent</code> events and forwards them to an external logging or analysis system. Useful for conversation analytics, compliance logging, or integration with CRM systems.</p>\n","urls":{"html":"/docs/guides/webhook-automation","text":"/docs/guides/webhook-automation?format=text","json":"/docs/guides/webhook-automation?format=json","llm":"/docs/guides/webhook-automation?format=llm"},"translations_available":["en","zh","hi","es","fr","ar","pt","ru","ja","de","it","ko","nl","pl","tr","sv","vi","th","id","uk"]}