{
  "id": "uSfPeWNVJz8cA6qv",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Daily Reconciliation - COPY",
  "tags": [],
  "nodes": [
    {
      "id": "6d1243f3-03d5-464f-9e9e-bf171931543f",
      "name": "Edit Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        -160,
        -240
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "485712c6-e749-4452-b12c-4eddb625f592",
              "name": "Link",
              "type": "string",
              "value": "=https://secure.telr.com/tools/api/xml/report/{{ $json.id }}/file2"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "eac73b4b-7d0a-494b-b7a8-8fe94010e857",
      "name": "Compression",
      "type": "n8n-nodes-base.compression",
      "position": [
        256,
        -240
      ],
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "567ca84c-5add-4bb6-ac0d-74d7127e6fcd",
      "name": "Extract from File",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        464,
        -240
      ],
      "parameters": {
        "options": {
          "sheetName": "Authorised"
        },
        "operation": "xls",
        "binaryPropertyName": "file_0"
      },
      "typeVersion": 1
    },
    {
      "id": "38fb4a85-3895-444c-98b0-a4e8da125cc7",
      "name": "Code in JavaScript3",
      "type": "n8n-nodes-base.code",
      "position": [
        -752,
        -16
      ],
      "parameters": {
        "jsCode": "return [\n  {\n    json: {\n      transactionsJson: JSON.stringify($json.transactions)\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "85288925-d942-415c-ad0c-bccbd40a7638",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -992,
        -240
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 9
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "69b46d09-691a-463f-a1cf-d387cd74e74a",
      "name": "Send email",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        -64,
        -32
      ],
      "parameters": {
        "html": "=<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"UTF-8\">\n</head>\n<body style=\"font-family: Arial, sans-serif; background:#f4f6f8; padding:20px;\">\n\n    <table width=\"600\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\" \n           style=\"background:#ffffff; padding:30px; border-radius:8px;\">\n\n        <tr>\n            <td align=\"center\">\n                <h2 style=\"margin:0; color:#1f2937;\">\n                    \ud83d\udcca Daily Telr Summary\n                </h2>\n                <p style=\"color:#6b7280; font-size:14px;\">\n                    Date: <strong>{{ $now.toFormat(\"yyyy-MM-dd\") }}</strong>\n                </p>\n            </td>\n        </tr>\n\n        <tr>\n            <td style=\"padding-top:20px; text-align:center;\">\n                \n                <div style=\"font-size:16px; color:#374151;\">\n                    Total Transactions Today\n                </div>\n\n                <div style=\"font-size:32px; font-weight:bold; color:#2563eb; margin-top:10px;\">\n                    {{\n                        $('Extract from File').all().length\n                    }}\n                </div>\n\n            </td>\n        </tr>\n\n        <tr>\n            <td style=\"padding-top:30px; text-align:center; font-size:12px; color:#9ca3af;\">\n                Automated report generated by n8n\n            </td>\n        </tr>\n\n    </table>\n\n</body>\n</html>\n",
        "options": {
          "appendAttribution": false
        },
        "subject": "Daily Auto Insert Telr Data",
        "toEmail": "user@example.com",
        "fromEmail": "user@example.com"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "05668922-02a9-44df-8bb6-11497940f3b3",
      "name": "TELR API",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -784,
        -240
      ],
      "parameters": {
        "url": "https://secure.telr.com/tools/api/xml/report",
        "options": {
          "response": {
            "response": {}
          }
        },
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth"
      },
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "2e8a77f9-b817-4214-b76d-43b6d3873fa1",
      "name": "Convert XML to JSON",
      "type": "n8n-nodes-base.xml",
      "position": [
        -576,
        -240
      ],
      "parameters": {
        "options": {},
        "dataPropertyName": "=data"
      },
      "typeVersion": 1
    },
    {
      "id": "05684b07-0d73-49b3-b67b-dfbaf29cafd6",
      "name": "Logic for date",
      "type": "n8n-nodes-base.code",
      "position": [
        -368,
        -240
      ],
      "parameters": {
        "jsCode": "// Get all reports\nconst reports = items[0].json.reports.report;\n\n// Calculate yesterday date in UTC\nconst yesterday = new Date();\nyesterday.setUTCDate(yesterday.getUTCDate() - 1);\n\n// Format YYYYMMDD\nconst yyyy = yesterday.getUTCFullYear();\nconst mm = String(yesterday.getUTCMonth() + 1).padStart(2, '0');\nconst dd = String(yesterday.getUTCDate()).padStart(2, '0');\nconst ymd = `${yyyy}${mm}${dd}`;\n\n// Filter yesterday's Daily transaction report\nconst result = reports.filter(r =>\n  r.description === 'Daily transaction report'&&\n  r.file2 &&\n  r.file2.includes(ymd)\n);\n\nreturn result.map(r => ({ json: r }));"
      },
      "typeVersion": 2
    },
    {
      "id": "2c468a45-cafe-45aa-be73-c0c02ae5d0d0",
      "name": "TELR API WITH DATE",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        48,
        -240
      ],
      "parameters": {
        "url": "={{ $json.Link }}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth"
      },
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "ca45596b-4743-42df-82f2-1089d7874284",
      "name": "Data Formation",
      "type": "n8n-nodes-base.code",
      "position": [
        -960,
        -16
      ],
      "parameters": {
        "jsCode": "return [\n  {\n    json: {\n      transactions: items.map(i => ({\n        column1: i.json['column1'],\n        column2: i.json['column2'],\n        column3: i.json['column3'],\n        column4: i.json['column4']\n      }))\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "98f88700-fc2c-4d4d-a427-0d535510ca30",
      "name": "Data Insert SQL",
      "type": "n8n-nodes-base.microsoftSql",
      "position": [
        -528,
        -16
      ],
      "parameters": {
        "query": "DECLARE @json NVARCHAR(MAX);\nSET @json = N'{{$json[\"transactionsJson\"]}}';\n\n-- IMPORTANT: terminate statement before OPENJSON\n;\n\nINSERT INTO authorised_transactions (\n    column1, column2, column3, column4 \n)\nSELECT\n    column1,\n    column2,\n    column3,\n    column4,\nFROM OPENJSON(@json)\nWITH (\n    column1 NVARCHAR(50),\n    column2 NVARCHAR(50),\n    column3 NVARCHAR(MAX),\n    column4 NVARCHAR(20)\n) t\nWHERE NOT EXISTS (\n    SELECT 1\n    FROM authorised_transactions_dates d\n    WHERE d.transaction_date = CONVERT(date, t.transaction_date, 103)\n);\n\nINSERT INTO authorised_transactions_dates (transaction_date)\nSELECT DISTINCT CONVERT(date, JSON_VALUE(value, '$.transaction_date'), 103)\nFROM OPENJSON(@json)\nWHERE NOT EXISTS (\n    SELECT 1 \n    FROM authorised_transactions_dates d \n    WHERE d.transaction_date = CONVERT(date, JSON_VALUE(value, '$.transaction_date'), 103)\n);\n\nSELECT 'SUCCESS' AS result;\n\n",
        "operation": "executeQuery"
      },
      "credentials": {
        "microsoftSql": {
          "name": "<your credential>"
        }
      },
      "executeOnce": false,
      "typeVersion": 1.1
    },
    {
      "id": "26465ebd-c8ca-4422-858c-de253d000fca",
      "name": "Success Condition",
      "type": "n8n-nodes-base.if",
      "position": [
        -320,
        -16
      ],
      "parameters": {
        "options": {
          "ignoreCase": "={{ false }}"
        },
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c46d4a8a-9407-4150-bdb4-11ba9d42ad1e",
              "operator": {
                "type": "string",
                "operation": "contains"
              },
              "leftValue": "={{ $json.result }}",
              "rightValue": "SUCCESS"
            }
          ]
        }
      },
      "executeOnce": true,
      "typeVersion": 2.3
    },
    {
      "id": "a9a8ceb7-da69-4763-a834-75df9b71df92",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1872,
        -464
      ],
      "parameters": {
        "width": 592,
        "height": 576,
        "content": "## Telr Scheduled Payment Report \u2192 SQL + Email\n\n\n**Who's it for**: Merchants and developers using Telr who need daily automated reconciliation of payment data stored to a SQL database.\n\n**What it does**: Fetches Telr transaction reports on a schedule, decompresses and parses the XLS file, transforms records with JavaScript, writes them to SQL, and sends a confirmation email.\n\n**How it works**:\n\n1. Schedule Trigger fires the workflow at your defined interval.\n2. Telr API fetches the raw transaction report.\n3. XML is converted to JSON for processing.\n4. Logic for Date calculates the relevant date range.\n5. Edit Fields maps and renames fields manually.\n6. Telr API with Date refetches with the computed date filter.\n7. Compression node decompresses the downloaded file.\n8. Extract from File reads the XLS content.\n9. Data Formation shapes the records for SQL.\n10. Code in JavaScript3 applies custom business logic.\n11. Data Insert SQL writes records to your database.\n12. Success Condition checks if the insert succeeded.\n13. Send Email dispatches a success notification."
      },
      "typeVersion": 1
    },
    {
      "id": "7f27cd1f-2005-4414-8967-3eb82158414d",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -720,
        -736
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 400,
        "content": "## Telr API Data and Formatting\n\n\nHTTP GET to https://secure.telr.com/... to retrieve the transaction report. Requires your Telr API key set as a credential in n8n. Returns an XML response.\n\n\nParses the raw XML body from the Telr API into a structured JSON object so downstream nodes can access fields using dot notation.\n\nA Code or Function node that computes the target date range (e.g., yesterday's date) to pass into the second Telr API call. Uses JavaScript date manipulation to format the date string in Telr's required format.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "5bdd8a4a-ca75-4f34-9ba4-b55e14cc988a",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        16,
        -736
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 400,
        "content": "## Data modifications\n\n\nManually maps and renames fields from the JSON object. Use this to standardise field names, remove unwanted keys, or prepare the payload for the date-filtered API call.\n\nSecond call to the Telr API, this time including the computed date range as query parameters. This fetches only the transactions for the relevant period and returns a compressed XLS file download link or binary.\n\nDecompresses the downloaded archive (e.g., .zip or .gz) returned by Telr. The output is the raw XLS file binary ready for extraction."
      },
      "typeVersion": 1
    },
    {
      "id": "128ce8fa-692c-4aa2-8a2f-1622b044257d",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -768,
        176
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 400,
        "content": "## Data Inserting\n\n\nRestructures and formats the extracted row data into the exact shape expected by the SQL INSERT statement. Maps XLS column names to database column names.\n\nCustom JavaScript logic applied to all items \u2014 e.g., type casting, deduplication checks, amount normalisation, or filtering out header rows. This is where you adapt the workflow to your specific data format.\n\nExecutes an INSERT or UPSERT query against your database (MySQL, PostgreSQL, etc.) for each processed transaction record. Configure your DB credentials and table name here."
      },
      "typeVersion": 1
    },
    {
      "id": "c7e345b3-4d03-41b9-882b-ac37af962bfe",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        192,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 400,
        "height": 400,
        "content": "## Notify after inserted\n\n\nAn IF node that checks the output of the SQL insert. Routes to the true branch (send email) on success, and to the false branch (optional error handler or no-op) on failure or empty result.\n\nSends a notification email confirming the report was processed and inserted successfully. Include a summary count of records inserted. Configure SMTP or Gmail credentials."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "12b2d8e4-845b-411f-8a5d-ff764ba5a05a",
  "connections": {
    "TELR API": {
      "main": [
        [
          {
            "node": "Convert XML to JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compression": {
      "main": [
        [
          {
            "node": "Extract from File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        [
          {
            "node": "TELR API WITH DATE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data Formation": {
      "main": [
        [
          {
            "node": "Code in JavaScript3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Logic for date": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data Insert SQL": {
      "main": [
        [
          {
            "node": "Success Condition",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "TELR API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract from File": {
      "main": [
        [
          {
            "node": "Data Formation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Success Condition": {
      "main": [
        [
          {
            "node": "Send email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "TELR API WITH DATE": {
      "main": [
        [
          {
            "node": "Compression",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript3": {
      "main": [
        [
          {
            "node": "Data Insert SQL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert XML to JSON": {
      "main": [
        [
          {
            "node": "Logic for date",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}