🔬 Check foreign card exchange rates with Google Sheets, Frankfurter and Slack

⚡ 1 views · 🔬 Document Extraction & Analysis

Description

Quick overview

This workflow runs monthly (or on demand) to read foreign-currency card charges from Google Sheets, fetch matching market exchange rates from the Frankfurter API, calculate premiums versus expected billed amounts, write results back to Google Sheets, and post a summary to Slack.

How it works

  1. Runs on a monthly schedule or when manually triggered.
  2. Reads charge rows from the “FX statement” tab in Google Sheets and identifies rows where the transaction currency differs from the configured base currency.
  3. Builds per-currency date ranges and requests historical exchange rates from the Frankfurter API for the required period.
  4. Calculates each charge’s effective rate, expected billed amount, premium percentage, and extra amount, and assigns a status such as OK, High premium, Below market, Rate unavailable, or Check data.
  5. Appends or updates the per-charge results in the “FX check” tab in Google Sheets using a stable row key to avoid duplicates on re-runs.
  6. Posts a Slack message summarizing totals, the highest premium charges, and any rows that need attention, or posts a “nothing to check” message if no foreign-currency rows are found.

Setup

  1. Create a Google Sheets OAuth2 credential, select your target spreadsheet in the Google Sheets nodes, and (optionally) run the provided setup branch after pasting your spreadsheet ID to create the “FX statement” and “FX check” tabs with headers.
  2. Add a Slack credential, choose the channel ID in the Slack message node, and ensure the bot is allowed to post to that channel.
  3. Paste your statement data into the “FX statement” tab and confirm the column names and base currency in the Config step match your sheet (Date, Merchant, Billed, Foreign amount, Currency by default).

Requirements

Customization

Additional info

What the numbers mean:

What I tested: 28 unit checks of the code, and one run against the live API on 10 made-up statement lines (amounts built from real market rates with chosen premiums): 2.5%, 3.0% and 2.0% OK; 4.5% and 6.2% flagged “High premium”; a line billed 7% below the market flagged “Below market”; AED “Rate unavailable”; a zero amount “Check data”; 3 domestic lines skipped; the Slack message arrived. The “nothing to check” branch was tested only in a unit test of the planning code, not run live. I had no real card CSV to test with.

đź”— Nodes Used

Google Sheets, HTTP Request, Slack, Schedule Trigger

📥 Import

Download workflow.json and import into n8n: Workflow menu → Import from File

📖 Importing guide · 🔑 Credential setup