Payment screenshot → AI reads it → log for checking
Customers send an InstaPay or wallet transfer screenshot to your Telegram bot; AI reads the amount and logs it for you to verify.
How it works
- A customer sends the transfer screenshot (with their order number as the caption).
- AI reads the amount, sender, reference and date from the image.
- The transfer is logged in a sheet with status "to verify", and the customer gets a receipt message.
- Unreadable images get a polite request for a clearer screenshot.
Diagram
Code
JavaScript used in the Code step — already included in the template below.
// Mode: Run Once for Each Item
// The AI read a transfer screenshot (InstaPay, wallet or bank) and was asked for JSON like:
// {"is_transfer": true, "amount": 1250, "currency": "EGP", "sender": "Ahmed M.", "reference": "123456789", "date": "2026-10-19"}
const match = $json.text.match(/\{[\s\S]*\}/);
const t = match ? JSON.parse(match[0]) : {};
const msg = $("Screenshot received").item.json.message;
return {
json: {
is_transfer: t.is_transfer === true && Number(t.amount) > 0,
amount: Number(t.amount) || 0,
currency: t.currency || "EGP",
sender: t.sender || "",
reference: t.reference || "",
date: t.date || "",
chatId: msg.chat.id,
caption: msg.caption || "",
},
};Build it
Pick your tool — same automation, step by step.
Copy and paste straight into an n8n canvas (Ctrl+V), or download and use Import from File. Then connect your own credentials and replace every YOUR_… placeholder. AI steps use a Claude model node — swap it for OpenAI, Gemini or Ollama if you prefer.
Show code (272 lines)
{
"name": "Payment screenshot → AI reads it → log for checking (Flowngn)",
"nodes": [
{
"parameters": {
"content": "## Payment screenshot → AI reads it → log for checking\nCustomers send an InstaPay or wallet transfer screenshot to your Telegram bot; AI reads the amount and logs it for you to verify.\n\n**Setup**\n1. Open each node and connect your own credentials.\n2. Replace every YOUR_… placeholder.\n3. Test once, then activate.\n\nFree template from Flowngn",
"height": 260,
"width": 340
},
"id": "35c47c31-9f0c-4ea1-ae8c-21fbe894577c",
"name": "Setup notes",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-420,
-60
]
},
{
"parameters": {
"updates": [
"message"
],
"additionalFields": {
"download": true
}
},
"id": "35c47c31-9f0c-4ea1-ae8c-21fbe894577c",
"name": "Screenshot received",
"type": "n8n-nodes-base.telegramTrigger",
"typeVersion": 1.1,
"position": [
0,
0
],
"webhookId": "35c47c31-9f0c-4ea1-ae8c-21fbe894577c"
},
{
"parameters": {
"promptType": "define",
"text": "=This image should be a payment transfer screenshot (InstaPay, mobile wallet or bank). Reply ONLY with JSON: {\"is_transfer\": true|false, \"amount\": number, \"currency\": \"EGP\", \"sender\": \"...\", \"reference\": \"...\", \"date\": \"YYYY-MM-DD\"}. If you can't read it clearly, set is_transfer to false. Never guess numbers.",
"passthroughBinaryImages": true
},
"id": "35c47c31-9f0c-4ea1-ae8c-21fbe894577c",
"name": "Read the transfer",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"typeVersion": 1.5,
"position": [
300,
0
]
},
{
"parameters": {
"model": {
"__rl": true,
"value": "claude-sonnet-5",
"mode": "list"
},
"options": {}
},
"id": "35c47c31-9f0c-4ea1-ae8c-21fbe894577c",
"name": "Claude model",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"typeVersion": 1.3,
"position": [
300,
220
]
},
{
"parameters": {
"jsCode": "// Mode: Run Once for Each Item\n// The AI read a transfer screenshot (InstaPay, wallet or bank) and was asked for JSON like:\n// {\"is_transfer\": true, \"amount\": 1250, \"currency\": \"EGP\", \"sender\": \"Ahmed M.\", \"reference\": \"123456789\", \"date\": \"2026-10-19\"}\nconst match = $json.text.match(/\\{[\\s\\S]*\\}/);\nconst t = match ? JSON.parse(match[0]) : {};\nconst msg = $(\"Screenshot received\").item.json.message;\n\nreturn {\n json: {\n is_transfer: t.is_transfer === true && Number(t.amount) > 0,\n amount: Number(t.amount) || 0,\n currency: t.currency || \"EGP\",\n sender: t.sender || \"\",\n reference: t.reference || \"\",\n date: t.date || \"\",\n chatId: msg.chat.id,\n caption: msg.caption || \"\",\n },\n};",
"mode": "runOnceForEachItem"
},
"id": "35c47c31-9f0c-4ea1-ae8c-21fbe894577c",
"name": "Read details",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
600,
0
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose"
},
"conditions": [
{
"id": "c1",
"leftValue": "={{ $json.is_transfer }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "35c47c31-9f0c-4ea1-ae8c-21fbe894577c",
"name": "Readable transfer?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
900,
0
]
},
{
"parameters": {
"operation": "append",
"documentId": {
"__rl": true,
"value": "YOUR_SPREADSHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "Transfers",
"mode": "name"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"received": "={{ $now.toISO() }}",
"amount": "={{ $json.amount }}",
"currency": "={{ $json.currency }}",
"sender": "={{ $json.sender }}",
"reference": "={{ $json.reference }}",
"order": "={{ $json.caption }}",
"status": "to verify"
}
},
"options": {}
},
"id": "35c47c31-9f0c-4ea1-ae8c-21fbe894577c",
"name": "Log for checking",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
1200,
0
]
},
{
"parameters": {
"chatId": "={{ $('Read details').item.json.chatId }}",
"text": "=✅ Received: {{ $('Read details').item.json.amount }} {{ $('Read details').item.json.currency }} from {{ $('Read details').item.json.sender }} — we'll confirm once it's verified.",
"additionalFields": {
"appendAttribution": false
}
},
"id": "35c47c31-9f0c-4ea1-ae8c-21fbe894577c",
"name": "Confirm receipt",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
1500,
0
]
},
{
"parameters": {
"chatId": "={{ $json.chatId }}",
"text": "Sorry, I couldn't read that. Please send a clear screenshot of the transfer confirmation.",
"additionalFields": {
"appendAttribution": false
}
},
"id": "35c47c31-9f0c-4ea1-ae8c-21fbe894577c",
"name": "Ask for a clearer image",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
1200,
220
]
}
],
"connections": {
"Screenshot received": {
"main": [
[
{
"node": "Read the transfer",
"type": "main",
"index": 0
}
]
]
},
"Read the transfer": {
"main": [
[
{
"node": "Read details",
"type": "main",
"index": 0
}
]
]
},
"Read details": {
"main": [
[
{
"node": "Readable transfer?",
"type": "main",
"index": 0
}
]
]
},
"Readable transfer?": {
"main": [
[
{
"node": "Log for checking",
"type": "main",
"index": 0
}
],
[
{
"node": "Ask for a clearer image",
"type": "main",
"index": 0
}
]
]
},
"Log for checking": {
"main": [
[
{
"node": "Confirm receipt",
"type": "main",
"index": 0
}
]
]
},
"Claude model": {
"ai_languageModel": [
[
{
"node": "Read the transfer",
"type": "ai_languageModel",
"index": 0
}
]
]
}
},
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"meta": {
"templateCredsSetupCompleted": false
},
"tags": []
}In Make, create a new scenario and add these modules in order:
- Telegram Bot › Watch Updates
- Anthropic Claude › Create a Prompt (or OpenAI › Create a Completion)
- Tools › Set variable / Iterator + Array aggregator (same logic as the Code step)
- Router with two routes: “Readable transfer?” (yes / no filters)
- If yesGoogle Sheets › Add a Row
- If noTelegram Bot › Send a Text Message or a Reply
- If yesTelegram Bot › Send a Text Message or a Reply
- Every module run uses Make operations — the free plan includes a monthly quota.
- Make's built-in functions (map, sum, formatDate…) can replace most Code steps; for complex logic use a code module.
- Module and step names can differ slightly as Make and Zapier update their apps.
In Zapier, create a new Zap and add these steps in order:
- Telegram — New Message
- Anthropic (Claude) — Send Message (or ChatGPT — Conversation)
- Code by Zapier — Run JavaScript (paste the code from the Code section)
- Paths by Zapier: “Readable transfer?” (yes / no)
- If yesGoogle Sheets — Create Spreadsheet Row
- If noTelegram — Send Message
- If yesTelegram — Send Message
- Zaps with more than two steps need a paid Zapier plan.
- Webhooks, Filters/Paths and Code by Zapier are premium features on some Zapier plans.
- Code by Zapier runs JavaScript: reuse the code shown above, reading inputs from inputData instead of $json.
- Module and step names can differ slightly as Make and Zapier update their apps.
Tips
- Always confirm the money actually arrived in your account before shipping — screenshots can be faked.
- Use an AI model that can read images.
Related flows
Log every Paymob payment in Google Sheets
Every Paymob transaction, successful or failed, becomes a row in your sheet.
Telegram alert for failed Paymob payments
Know instantly when a customer's payment fails, so you can call them and save the sale.
Verify Paymob callbacks with HMAC
Check Paymob's signature on every callback so fake payment messages are rejected.