{
"updatedAt": "2025-12-10T02:57:45.000Z",
"createdAt": "2025-12-06T15:19:57.039Z",
"id": "ZbhpBjrE6yE4dSFH",
"name": "Geni_AI_YooKassa_webhook",
"description": null,
"active": true,
"isArchived": false,
"nodes": [
{
"parameters": {
"jsCode": "// Code node: yk_extract_payment\n// Вход: сырой webhook от YooKassa (как в примере из pinData)\n// Выход: нормализованный объект, удобный для дальнейшей логики:\n//\n// {\n// event: \"payment.succeeded\",\n// type: \"notification\",\n// payment_id: \"...\",\n// status: \"succeeded\",\n// paid: true,\n// test: true,\n// amount_value: \"199.00\",\n// amount_currency: \"RUB\",\n// income_value: \"192.03\",\n// income_currency: \"RUB\",\n// metadata: { ... },\n// tg_chat_id: \"748140117\",\n// credits: 200,\n// product: \"credits\",\n// skip: false // если событие не то / не оплачено — будет true\n// }\n\nconst headers = $json.headers || {};\nconst body = $json.body || {};\n\nconst event = String(body.event || '');\nconst type = String(body.type || '');\n\nconst obj = body.object || {};\n\nconst paymentId = obj.id || null;\nconst status = String(obj.status || '');\nconst paid = Boolean(obj.paid);\nconst test = Boolean(obj.test);\n\n// amount / income_amount\nconst amount = obj.amount || {};\nconst incomeAmount = obj.income_amount || {};\n\nconst amount_value = String(amount.value || '');\nconst amount_currency = String(amount.currency || '');\nconst income_value = String(incomeAmount.value || '');\nconst income_currency = String(incomeAmount.currency || '');\n\n// metadata (мы туда кладём tg_chat_id, credits, product)\nconst metadata = obj.metadata || {};\nconst tg_chat_id = String(metadata.tg_chat_id || metadata.tg_user_id || '');\nconst product = String(metadata.product || metadata.product_code || '');\nconst lang = (metadata.lang === 'en') ? 'en' : 'ru';\n\nlet credits = null;\nif (metadata.credits !== undefined) {\n const c = Number(metadata.credits);\n if (Number.isFinite(c)) credits = c;\n}\n\n// Флаг: можно ли обрабатывать платёж дальше\nconst isSucceeded = (\n event === 'payment.succeeded' &&\n status === 'succeeded' &&\n paid === true\n);\n\n// Если что-то не так, дальше по потоку можно будет отфильтровать по skip = true\nconst skip = !isSucceeded;\n\nreturn [{\n json: {\n event,\n type,\n payment_id: paymentId,\n status,\n paid,\n test,\n\n amount_value,\n amount_currency,\n income_value,\n income_currency,\n\n metadata,\n tg_chat_id,\n credits,\n product,\n lang,\n // тех.инфа для отладок (по желанию)\n raw_signature: headers.signature || null,\n\n skip,\n }\n}];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
224,
0
],
"id": "49366e13-1c24-4523-923f-9bbc1041ebc4",
"name": "yk_extract_payment"
},
{
"parameters": {
"httpMethod": "POST",
"path": "yookassa",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
0,
0
],
"id": "0cf11d53-19e3-43fb-90e7-c135dd7dc6df",
"name": "Webhook",
"webhookId": "e6423b70-6fb5-430c-8a1f-d5ea49363825"
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"leftValue": "={{ $json.skip }}",
"rightValue": false,
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
},
"id": "6734d3a4-fe94-4625-879b-9f704153f34a"
}
],
"combinator": "and"
}
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "0f426f9c-5a56-495f-b309-95ec8f20a582",
"leftValue": "={{ $json.skip }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
}
}
]
},
"options": {}
},
"type": "n8n-nodes-base.switch",
"typeVersion": 3.3,
"position": [
432,
0
],
"id": "66db1850-c3f5-4375-8ca3-7b2b528c2b63",
"name": "Switch"
},
{
"parameters": {
"method": "POST",
"url": "=https://bwbsclwdkighhzlyiman.supabase.co/rest/v1/rpc/apply_telegram_payment",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "supabaseApi",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": " application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"p_tg_user_id\": {{ $json.metadata.tg_chat_id }},\n \"p_provider\": \"yookassa\",\n \"p_charge_id\": \"{{ $json.payment_id }}\",\n \"p_currency\": \"{{ $json.amount_currency }}\",\n \"p_amount\": {{ $json.amount_value }},\n \"p_product_kind\": \"{{ $json.metadata.product || 'credits' }}\",\n \"p_product_code\": \"{{ $json.metadata.credits }}\",\n \"p_credits_added\": {{ $json.credits || 0 }},\n \"p_plan\": null,\n \"p_plan_days\": 0,\n \"p_lang\": \"{{ $json.lang || 'ru' }}\"\n}\n",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
672,
0
],
"id": "e2ed7295-0a62-42b8-94f4-740c43d93d68",
"name": "yk_apply_payment",
"credentials": {
"supabaseApi": {
"id": "jGgpXKPYHiL193Rz",
"name": "Supabase account"
}
}
},
{
"parameters": {
"chatId": "={{ $('yk_extract_payment').item.json.tg_chat_id }}",
"text": "={{\n $('yk_extract_payment').item.json.lang === 'en'\n ? (\n '✅ Card payment via YooMoney (YuKassa) was successful.\\n' +\n 'Credits added: +' + ( $('yk_extract_payment').item.json.credits || 0 ) + '\\n' +\n 'Amount: ' +\n ( $('yk_extract_payment').item.json.amount_value || '' ) + ' ' +\n ( $('yk_extract_payment').item.json.amount_currency || '' ) + '\\n' +\n 'New balance: ' + ($json.balance ?? $json.new_balance) + ' credits.'\n )\n : (\n '✅ Оплата через ЮMoney (ЮKassa) прошла успешно.\\n' +\n 'Кредиты начислены: +' + ( $('yk_extract_payment').item.json.credits || 0 ) + '\\n' +\n 'Сумма: ' +\n ( $('yk_extract_payment').item.json.amount_value || '' ) + ' ' +\n ( $('yk_extract_payment').item.json.amount_currency || '' ) + '\\n' +\n 'Новый баланс: ' + ($json.balance ?? $json.new_balance) + ' кредитов.'\n )\n}}",
"additionalFields": {
"appendAttribution": false
}
},
"id": "52a31127-882a-47e2-bca9-ee4ef49e68ae",
"name": "yk_payment_ack",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
880,
0
],
"webhookId": "124d7029-df2d-4781-9f2b-14f1f6d7ebfc",
"credentials": {
"telegramApi": {
"id": "ur7jSUPdiAaPVhCf",
"name": "Geni AI"
}
}
},
{
"parameters": {
"operation": "deleteMessage",
"chatId": "={{ $json.chat_id }}",
"messageId": "={{ $json.message_id }}"
},
"id": "842bacea-334b-4659-a36c-2bf9fdc8326f",
"name": "delMes3",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
1088,
208
],
"webhookId": "71f626cd-d5a3-4dd8-8a6d-3fd0176ac380",
"credentials": {
"telegramApi": {
"id": "ur7jSUPdiAaPVhCf",
"name": "Geni AI"
}
}
},
{
"parameters": {
"operation": "getAll",
"tableId": "payment_messages",
"limit": 1,
"filters": {
"conditions": [
{
"keyName": "charge_id",
"condition": "eq",
"keyValue": "={{ $('yk_extract_payment').item.json.payment_id }}"
}
]
}
},
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
880,
208
],
"id": "1702c426-d88b-41d6-a498-eb237f856577",
"name": "get_payment_message",
"credentials": {
"supabaseApi": {
"id": "jGgpXKPYHiL193Rz",
"name": "Supabase account"
}
}
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "yk_extract_payment",
"type": "main",
"index": 0
}
]
]
},
"yk_extract_payment": {
"main": [
[
{
"node": "Switch",
"type": "main",
"index": 0
}
]
]
},
"Switch": {
"main": [
[
{
"node": "yk_apply_payment",
"type": "main",
"index": 0
}
]
]
},
"yk_apply_payment": {
"main": [
[
{
"node": "yk_payment_ack",
"type": "main",
"index": 0
},
{
"node": "get_payment_message",
"type": "main",
"index": 0
}
]
]
},
"yk_payment_ack": {
"main": [
[]
]
},
"get_payment_message": {
"main": [
[
{
"node": "delMes3",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"meta": null,
"pinData": {
"Webhook": [
{
"json": {
"headers": {
"host": "n8n.geni-ai.online",
"user-agent": "AHC/2.1",
"content-length": "1112",
"accept": "*/*",
"accept-encoding": "gzip, br",
"cdn-loop": "cloudflare; loops=1",
"cf-connecting-ip": "77.75.153.78",
"cf-ipcountry": "RU",
"cf-ray": "9a9dd568ffefb69e-HEL",
"cf-visitor": "{\"scheme\":\"https\"}",
"cf-warp-tag-id": "ac2f4890-4e5c-408a-acd2-00718c3f328f",
"connection": "keep-alive",
"content-type": "application/json",
"signature": "v1 30c68927 1 MGQCMDjevzamw9k18AXXh4ZuUGp4CSQGkSB9eZCtG3kx4FrGhiSIbgdsPQn8OHspSFb7HAIwayQ99vtDSVO2pNPB2XgYEvjODJCF+wb973StfbSYs0h9O/NFjqELeD3CANsHUo7O",
"x-forwarded-for": "77.75.153.78",
"x-forwarded-proto": "https"
},
"params": {},
"query": {},
"body": {
"type": "notification",
"event": "payment.succeeded",
"object": {
"id": "30c6891b-000f-5001-8000-1f3e3362c6a8",
"status": "succeeded",
"amount": {
"value": "899.00",
"currency": "RUB"
},
"income_amount": {
"value": "867.53",
"currency": "RUB"
},
"description": "Пакет 1000 кредитов. TG: 748140117",
"recipient": {
"account_id": "1221831",
"gateway_id": "2594797"
},
"payment_method": {
"type": "yoo_money",
"id": "30c6891b-000f-5001-8000-1f3e3362c6a8",
"saved": false,
"status": "inactive",
"title": "YooMoney wallet 410011758831136",
"account_number": "410011758831136"
},
"captured_at": "2025-12-06T18:26:47.650Z",
"created_at": "2025-12-06T18:26:35.400Z",
"test": true,
"refunded_amount": {
"value": "0.00",
"currency": "RUB"
},
"paid": true,
"refundable": true,
"metadata": {
"product": "credits",
"tg_chat_id": "748140117",
"lang": "en",
"credits": "1000"
}
}
},
"webhookUrl": "https://n8n.geni-ai.online/webhook/yookassa",
"executionMode": "production"
}
}
]
},
"versionId": "cb959e2d-8109-4924-8748-ffce03505520",
"activeVersionId": "cb959e2d-8109-4924-8748-ffce03505520",
"versionCounter": 30,
"triggerCount": 1,
"shared": [
{
"updatedAt": "2025-12-06T15:19:57.043Z",
"createdAt": "2025-12-06T15:19:57.043Z",
"role": "workflow:owner",
"workflowId": "ZbhpBjrE6yE4dSFH",
"projectId": "MHclKTSzdRCLxmxU",
"project": {
"updatedAt": "2025-05-06T12:49:51.317Z",
"createdAt": "2025-05-06T12:48:38.577Z",
"id": "MHclKTSzdRCLxmxU",
"name": "Grigoriy Voyakin <grigoriyvoyakinwork@gmail.com>",
"type": "personal",
"icon": null,
"description": null,
"projectRelations": [
{
"updatedAt": "2025-05-06T12:48:38.577Z",
"createdAt": "2025-05-06T12:48:38.577Z",
"userId": "15659665-1e18-4119-8f87-b50a3cb257b7",
"projectId": "MHclKTSzdRCLxmxU",
"user": {
"updatedAt": "2025-12-10T02:57:46.000Z",
"createdAt": "2025-05-06T12:48:38.340Z",
"id": "15659665-1e18-4119-8f87-b50a3cb257b7",
"email": "grigoriyvoyakinwork@gmail.com",
"firstName": "Grigoriy",
"lastName": "Voyakin",
"personalizationAnswers": {
"version": "v4",
"personalization_survey_submitted_at": "2025-05-09T12:49:28.002Z",
"personalization_survey_n8n_version": "1.91.3"
},
"settings": {
"userActivated": true,
"easyAIWorkflowOnboarded": true,
"firstSuccessfulWorkflowId": "6ndVsjNc12yZ7vD6",
"userActivatedAt": 1747397744116,
"npsSurvey": {
"responded": true,
"lastShownAt": 1756144477136
}
},
"disabled": false,
"mfaEnabled": false,
"lastActiveAt": "2025-12-09",
"isPending": false
}
}
]
}
}
],
"tags": [
{
"updatedAt": "2025-10-29T09:15:49.403Z",
"createdAt": "2025-10-29T09:15:49.403Z",
"id": "NFsjRzvK9b3zMBTF",
"name": "docs"
}
],
"activeVersion": {
"updatedAt": "2025-12-10T02:57:45.109Z",
"createdAt": "2025-12-10T02:57:45.109Z",
"versionId": "cb959e2d-8109-4924-8748-ffce03505520",
"workflowId": "ZbhpBjrE6yE4dSFH",
"nodes": [
{
"parameters": {
"jsCode": "// Code node: yk_extract_payment\n// Вход: сырой webhook от YooKassa (как в примере из pinData)\n// Выход: нормализованный объект, удобный для дальнейшей логики:\n//\n// {\n// event: \"payment.succeeded\",\n// type: \"notification\",\n// payment_id: \"...\",\n// status: \"succeeded\",\n// paid: true,\n// test: true,\n// amount_value: \"199.00\",\n// amount_currency: \"RUB\",\n// income_value: \"192.03\",\n// income_currency: \"RUB\",\n// metadata: { ... },\n// tg_chat_id: \"748140117\",\n// credits: 200,\n// product: \"credits\",\n// skip: false // если событие не то / не оплачено — будет true\n// }\n\nconst headers = $json.headers || {};\nconst body = $json.body || {};\n\nconst event = String(body.event || '');\nconst type = String(body.type || '');\n\nconst obj = body.object || {};\n\nconst paymentId = obj.id || null;\nconst status = String(obj.status || '');\nconst paid = Boolean(obj.paid);\nconst test = Boolean(obj.test);\n\n// amount / income_amount\nconst amount = obj.amount || {};\nconst incomeAmount = obj.income_amount || {};\n\nconst amount_value = String(amount.value || '');\nconst amount_currency = String(amount.currency || '');\nconst income_value = String(incomeAmount.value || '');\nconst income_currency = String(incomeAmount.currency || '');\n\n// metadata (мы туда кладём tg_chat_id, credits, product)\nconst metadata = obj.metadata || {};\nconst tg_chat_id = String(metadata.tg_chat_id || metadata.tg_user_id || '');\nconst product = String(metadata.product || metadata.product_code || '');\nconst lang = (metadata.lang === 'en') ? 'en' : 'ru';\n\nlet credits = null;\nif (metadata.credits !== undefined) {\n const c = Number(metadata.credits);\n if (Number.isFinite(c)) credits = c;\n}\n\n// Флаг: можно ли обрабатывать платёж дальше\nconst isSucceeded = (\n event === 'payment.succeeded' &&\n status === 'succeeded' &&\n paid === true\n);\n\n// Если что-то не так, дальше по потоку можно будет отфильтровать по skip = true\nconst skip = !isSucceeded;\n\nreturn [{\n json: {\n event,\n type,\n payment_id: paymentId,\n status,\n paid,\n test,\n\n amount_value,\n amount_currency,\n income_value,\n income_currency,\n\n metadata,\n tg_chat_id,\n credits,\n product,\n lang,\n // тех.инфа для отладок (по желанию)\n raw_signature: headers.signature || null,\n\n skip,\n }\n}];\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
224,
0
],
"id": "49366e13-1c24-4523-923f-9bbc1041ebc4",
"name": "yk_extract_payment"
},
{
"parameters": {
"httpMethod": "POST",
"path": "yookassa",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
0,
0
],
"id": "0cf11d53-19e3-43fb-90e7-c135dd7dc6df",
"name": "Webhook",
"webhookId": "e6423b70-6fb5-430c-8a1f-d5ea49363825"
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"leftValue": "={{ $json.skip }}",
"rightValue": false,
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
},
"id": "6734d3a4-fe94-4625-879b-9f704153f34a"
}
],
"combinator": "and"
}
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 2
},
"conditions": [
{
"id": "0f426f9c-5a56-495f-b309-95ec8f20a582",
"leftValue": "={{ $json.skip }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
}
}
]
},
"options": {}
},
"type": "n8n-nodes-base.switch",
"typeVersion": 3.3,
"position": [
432,
0
],
"id": "66db1850-c3f5-4375-8ca3-7b2b528c2b63",
"name": "Switch"
},
{
"parameters": {
"method": "POST",
"url": "=https://bwbsclwdkighhzlyiman.supabase.co/rest/v1/rpc/apply_telegram_payment",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "supabaseApi",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": " application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"p_tg_user_id\": {{ $json.metadata.tg_chat_id }},\n \"p_provider\": \"yookassa\",\n \"p_charge_id\": \"{{ $json.payment_id }}\",\n \"p_currency\": \"{{ $json.amount_currency }}\",\n \"p_amount\": {{ $json.amount_value }},\n \"p_product_kind\": \"{{ $json.metadata.product || 'credits' }}\",\n \"p_product_code\": \"{{ $json.metadata.credits }}\",\n \"p_credits_added\": {{ $json.credits || 0 }},\n \"p_plan\": null,\n \"p_plan_days\": 0,\n \"p_lang\": \"{{ $json.lang || 'ru' }}\"\n}\n",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
672,
0
],
"id": "e2ed7295-0a62-42b8-94f4-740c43d93d68",
"name": "yk_apply_payment",
"credentials": {
"supabaseApi": {
"id": "jGgpXKPYHiL193Rz",
"name": "Supabase account"
}
}
},
{
"parameters": {
"chatId": "={{ $('yk_extract_payment').item.json.tg_chat_id }}",
"text": "={{\n $('yk_extract_payment').item.json.lang === 'en'\n ? (\n '✅ Card payment via YooMoney (YuKassa) was successful.\\n' +\n 'Credits added: +' + ( $('yk_extract_payment').item.json.credits || 0 ) + '\\n' +\n 'Amount: ' +\n ( $('yk_extract_payment').item.json.amount_value || '' ) + ' ' +\n ( $('yk_extract_payment').item.json.amount_currency || '' ) + '\\n' +\n 'New balance: ' + ($json.balance ?? $json.new_balance) + ' credits.'\n )\n : (\n '✅ Оплата через ЮMoney (ЮKassa) прошла успешно.\\n' +\n 'Кредиты начислены: +' + ( $('yk_extract_payment').item.json.credits || 0 ) + '\\n' +\n 'Сумма: ' +\n ( $('yk_extract_payment').item.json.amount_value || '' ) + ' ' +\n ( $('yk_extract_payment').item.json.amount_currency || '' ) + '\\n' +\n 'Новый баланс: ' + ($json.balance ?? $json.new_balance) + ' кредитов.'\n )\n}}",
"additionalFields": {
"appendAttribution": false
}
},
"id": "52a31127-882a-47e2-bca9-ee4ef49e68ae",
"name": "yk_payment_ack",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
880,
0
],
"webhookId": "124d7029-df2d-4781-9f2b-14f1f6d7ebfc",
"credentials": {
"telegramApi": {
"id": "ur7jSUPdiAaPVhCf",
"name": "Geni AI"
}
}
},
{
"parameters": {
"operation": "deleteMessage",
"chatId": "={{ $json.chat_id }}",
"messageId": "={{ $json.message_id }}"
},
"id": "842bacea-334b-4659-a36c-2bf9fdc8326f",
"name": "delMes3",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
1088,
208
],
"webhookId": "71f626cd-d5a3-4dd8-8a6d-3fd0176ac380",
"credentials": {
"telegramApi": {
"id": "ur7jSUPdiAaPVhCf",
"name": "Geni AI"
}
}
},
{
"parameters": {
"operation": "getAll",
"tableId": "payment_messages",
"limit": 1,
"filters": {
"conditions": [
{
"keyName": "charge_id",
"condition": "eq",
"keyValue": "={{ $('yk_extract_payment').item.json.payment_id }}"
}
]
}
},
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
880,
208
],
"id": "1702c426-d88b-41d6-a498-eb237f856577",
"name": "get_payment_message",
"credentials": {
"supabaseApi": {
"id": "jGgpXKPYHiL193Rz",
"name": "Supabase account"
}
}
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "yk_extract_payment",
"type": "main",
"index": 0
}
]
]
},
"yk_extract_payment": {
"main": [
[
{
"node": "Switch",
"type": "main",
"index": 0
}
]
]
},
"Switch": {
"main": [
[
{
"node": "yk_apply_payment",
"type": "main",
"index": 0
}
]
]
},
"yk_apply_payment": {
"main": [
[
{
"node": "yk_payment_ack",
"type": "main",
"index": 0
},
{
"node": "get_payment_message",
"type": "main",
"index": 0
}
]
]
},
"yk_payment_ack": {
"main": [
[]
]
},
"get_payment_message": {
"main": [
[
{
"node": "delMes3",
"type": "main",
"index": 0
}
]
]
}
},
"authors": "Grigoriy Voyakin",
"name": null,
"description": null
}
}