This workflow follows the Postgres → Telegram recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "Theorem Reach Webhook",
"tags": [
"styxproxy",
"free-trial",
"theorem-reach",
"webhook"
],
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "theorem-reach",
"responseMode": "lastNode",
"options": {}
},
"id": "tr-webhook",
"name": "Theorem Reach Postback",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
250,
300
]
},
{
"parameters": {
"jsCode": "// Verify HMAC-SHA256 signature from Theorem Reach\nconst crypto = require('crypto');\n\nconst payload = $input.item.json.body || {};\nconst headers = $input.item.json.headers || {};\n\n// Theorem Reach sends signature in x-theorem-reach-signature header\nconst signature = headers['x-theorem-reach-signature'] || payload.signature;\nconst secret = process.env.THEOREM_REACH_SECRET;\n\nif (!secret) {\n throw new Error('THEOREM_REACH_SECRET not set in env');\n}\n\n// Theorem Reach signs: sha256(secret + transaction_id + user_id + payout_usd)\nconst message = `${secret}${payload.transaction_id}${payload.user_id}${payload.payout_usd}`;\nconst expected = crypto.createHash('sha256').update(message).digest('hex');\n\nconst valid = (signature === expected);\n\nreturn {\n json: {\n signature_valid: valid,\n raw_payload: payload,\n transaction_id: payload.transaction_id || '',\n user_id: payload.user_id || '',\n payout_usd: parseFloat(payload.payout_usd) || 0,\n status: payload.status || ''\n }\n};"
},
"id": "tr-verify",
"name": "Verify HMAC Signature",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
470,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose"
},
"conditions": [
{
"id": "cond-valid",
"leftValue": "={{$json.signature_valid}}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true"
}
}
]
},
"options": {}
},
"id": "tr-if-valid",
"name": "If Signature Valid",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
690,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "loose"
},
"conditions": [
{
"id": "cond-completed",
"leftValue": "={{$json.status}}",
"rightValue": "completed",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"options": {}
},
"id": "tr-if-completed",
"name": "If Status=Completed",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
910,
300
]
},
{
"parameters": {
"command": "SELECT user_id FROM theorem_reach_postbacks WHERE transaction_id = '{{$json.transaction_id}}';",
"options": {}
},
"id": "tr-check-idem",
"name": "Check Idempotency",
"type": "n8n-nodes-base.postgres",
"typeVersion": 1,
"position": [
1130,
300
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "loose"
},
"conditions": [
{
"id": "cond-new",
"leftValue": "={{$json.user_id}}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "empty"
}
}
]
},
"options": {}
},
"id": "tr-if-new",
"name": "If Not Already Processed",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
1350,
300
]
},
{
"parameters": {
"operation": "insert",
"schema": "public",
"table": "theorem_reach_postbacks",
"columns": "transaction_id,user_id,payout_usd,signature,signature_valid,raw_payload,processed_at",
"additionalFields": "{\n \"signature_valid\": {{$json.signature_valid}},\n \"raw_payload\": {{$json.raw_payload}}\n}",
"options": {}
},
"id": "tr-insert-postback",
"name": "Insert Postback Record",
"type": "n8n-nodes-base.postgres",
"typeVersion": 1,
"position": [
1570,
300
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Record the survey in pending_trial_surveys\n// Lookup platform_account by the user_id field (this is the Telegram chat_id for Styxproxy trials)\nconst payload = $input.item.json.raw_payload;\nconst userId = payload.user_id || '';\n\n// userId format from Theorem Reach for Styxproxy: contains the platform info\n// We store it as-is \u2014 the lookup happens at \"done\" time\nreturn {\n json: {\n survey_transaction_id: payload.transaction_id || '',\n survey_user_id: userId,\n payout_usd: parseFloat(payload.payout_usd) || 0,\n platform_user_id: userId, // Use user_id as the platform identifier\n platform: 'telegram', // Theorem Reach trials are triggered from Telegram for Styxproxy\n credited: false\n }\n};"
},
"id": "tr-prep-pending",
"name": "Prep Pending Survey Record",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1790,
300
]
},
{
"parameters": {
"operation": "insert",
"schema": "public",
"table": "pending_trial_surveys",
"columns": "survey_transaction_id,survey_user_id,payout_usd,platform_user_id,platform,credited",
"additionalFields": "{}",
"options": {}
},
"id": "tr-insert-pending",
"name": "Insert Pending Trial Survey",
"type": "n8n-nodes-base.postgres",
"typeVersion": 1,
"position": [
2010,
300
],
"credentials": {
"postgres": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Log the successful survey recording\nreturn {\n json: {\n logged: true,\n transaction_id: $input.item.json.transaction_id,\n user_id: $input.item.json.user_id,\n payout_usd: $input.item.json.payout_usd\n }\n};"
},
"id": "tr-log",
"name": "Log Survey Recorded",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2230,
300
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "{\"status\":\"ok\"}",
"options": {
"responseCode": 200
}
},
"id": "tr-respond-ok",
"name": "Respond 200 OK",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
2450,
300
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "{\"status\":\"already_processed\"}",
"options": {
"responseCode": 200
}
},
"id": "tr-respond-idem",
"name": "Respond 200 (Idempotent)",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
1570,
480
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "{\"status\":\"invalid_signature\"}",
"options": {
"responseCode": 401
}
},
"id": "tr-respond-401",
"name": "Respond 401 Unauthorized",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
910,
480
]
},
{
"parameters": {
"jsCode": "// Alert admin on invalid signature \u2014 possible attack\nreturn {\n json: {\n alert_admin: true,\n event: 'theorem_reach_invalid_signature',\n transaction_id: $input.item.json.transaction_id,\n user_id: $input.item.json.user_id\n }\n};"
},
"id": "tr-alert-invalid",
"name": "Alert Admin (Invalid Signature)",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1130,
480
]
},
{
"parameters": {
"chatId": "={{ $env.ADMIN_TELEGRAM_CHAT_ID }}",
"message": "\u26a0\ufe0f Theorem Reach invalid signature! Possible attack.\\nTX: {{$json.transaction_id}}\\nUser: {{$json.user_id}}",
"options": {}
},
"id": "tr-alert-tg",
"name": "Alert Admin via Telegram",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1,
"position": [
1350,
480
],
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Log completion event\nreturn { json: { event: 'theorem_reach_completed' } };"
},
"id": "tr-log-completion",
"name": "Log Completion",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1130,
200
]
}
],
"connections": {
"Theorem Reach Postback": {
"main": [
[
{
"node": "Verify HMAC Signature",
"type": "main",
"index": 0
}
]
]
},
"Verify HMAC Signature": {
"main": [
[
{
"node": "If Signature Valid",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond 401 Unauthorized",
"type": "main",
"index": 0
}
]
]
},
"If Signature Valid": {
"main": [
[
{
"node": "Log Completion",
"type": "main",
"index": 0
}
],
[
{
"node": "Alert Admin (Invalid Signature)",
"type": "main",
"index": 0
}
]
]
},
"Log Completion": {
"main": [
[
{
"node": "If Status=Completed",
"type": "main",
"index": 0
}
]
]
},
"Alert Admin (Invalid Signature)": {
"main": [
[
{
"node": "Alert Admin via Telegram",
"type": "main",
"index": 0
}
]
]
},
"Alert Admin via Telegram": {
"main": [
[
{
"node": "Respond 401 Unauthorized",
"type": "main",
"index": 0
}
]
]
},
"If Status=Completed": {
"main": [
[
{
"node": "Check Idempotency",
"type": "main",
"index": 0
}
]
]
},
"Check Idempotency": {
"main": [
[
{
"node": "If Not Already Processed",
"type": "main",
"index": 0
}
]
]
},
"If Not Already Processed": {
"main": [
[
{
"node": "Insert Postback Record",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond 200 (Idempotent)",
"type": "main",
"index": 0
}
]
]
},
"Insert Postback Record": {
"main": [
[
{
"node": "Prep Pending Survey Record",
"type": "main",
"index": 0
}
]
]
},
"Prep Pending Survey Record": {
"main": [
[
{
"node": "Insert Pending Trial Survey",
"type": "main",
"index": 0
}
]
]
},
"Insert Pending Trial Survey": {
"main": [
[
{
"node": "Log Survey Recorded",
"type": "main",
"index": 0
}
]
]
},
"Log Survey Recorded": {
"main": [
[
{
"node": "Respond 200 OK",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
postgrestelegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Theorem Reach Webhook. Uses postgres, telegram. Webhook trigger; 16 nodes.
Source: https://github.com/sonnyagent30-beep/bunche/blob/e991131928c348097e3fb411d5caa3b0466900f8/.n8n/workflows/theorem-reach-webhook.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Admin Handler. Uses telegram, postgres. Webhook trigger; 50 nodes.
Settings. Uses httpRequest, postgres, telegram. Webhook trigger; 38 nodes.
This n8n workflow automates task creation and scheduled reminders for users via a Telegram bot, ensuring timely notifications across multiple channels like email and Slack. It streamlines task managem
Teams that need a manager approval step before a ticket or request can change status. Great for internal ops, IT requests, or any workflow where “a human must sign off.” 📨 Manager receives approval/re