{
  "openapi": "3.1.1",
  "info": {
    "title": "Travel Exchange Fee Calculator API",
    "version": "1.0.0",
    "summary": "Compare what cards, ATMs, DCC and exchange bureaus really cost abroad vs the ECB reference rate.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://travelexchangefeecalculator.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Compare what cards, ATMs, DCC and exchange bureaus really cost abroad vs the ECB reference rate.",
        "description": "Enter what you spend abroad and the terms of your payment options – foreign transaction fee, exchange-rate mark-up, ATM fees, “pay in your currency” (dynamic currency conversion) and exchange-bureau spreads. The calculator converts at the ECB reference rate (or your own rate) and shows the effective rate, total cost and extra cost of each option, cheapest first.\n\nMethodology:\n- Reference cost = amount ÷ reference rate (the ECB euro reference rate, cross-calculated via EUR for non-euro pairs, or your manual rate).\n- Each option: cost at its own rate = reference cost × (1 + mark-up %); plus the percentage fee on that amount; plus fixed fees (ATM fixed fees × number of withdrawals). Effective rate = amount ÷ total cost; extra cost = total − reference cost.\n- Dynamic currency conversion (DCC, “pay in your currency”) means the shop’s or ATM operator’s provider converts instead of your card issuer; its mark-up is entered as a rate mark-up. Under Regulation (EU) 2019/518 DCC providers and card issuers in the EU must express their conversion charges as a mark-up over the latest ECB reference rate before you pay, which is the comparison this tool makes.\n- The default rows are illustrative example values, not market data. Replace them with your card’s published terms and the mark-up shown on the terminal or at the exchange counter.\n\nAn estimate: the rate your card network applies on the booking day and any fees not entered here change the final amount.",
        "tags": [
          "money"
        ],
        "x-mcp-tool": "travel_exchange_fee_calculator",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TravelExchangeFeeCalculatorInput"
              },
              "examples": {
                "example1": {
                  "summary": "500 USD with the example options (manual rate 1 EUR = 1.10 USD)",
                  "value": {
                    "amount": 500,
                    "spendCurrency": "USD",
                    "homeCurrency": "EUR",
                    "rateSource": "manual",
                    "manualRate": 1.1
                  }
                },
                "example2": {
                  "summary": "20,000 JPY, 2 ATM withdrawals (manual rate 1 GBP = 190 JPY)",
                  "value": {
                    "amount": 20000,
                    "spendCurrency": "JPY",
                    "homeCurrency": "GBP",
                    "rateSource": "manual",
                    "manualRate": 190,
                    "atmWithdrawals": 2,
                    "options": [
                      {
                        "name": "Travel card",
                        "method": "card",
                        "feePercent": 0,
                        "markupPercent": 0.4,
                        "fixedFee": 0
                      },
                      {
                        "name": "High-street bank ATM",
                        "method": "atm",
                        "feePercent": 2.99,
                        "markupPercent": 0,
                        "fixedFee": 1.5
                      },
                      {
                        "name": "DCC offer at the ATM",
                        "method": "dcc",
                        "feePercent": 0,
                        "markupPercent": 8,
                        "fixedFee": 1.5
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TravelExchangeFeeCalculatorResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "TravelExchangeFeeCalculatorInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "amount": {
            "title": "Amount spent abroad",
            "description": "In the local (spending) currency.",
            "type": "number",
            "minimum": 0.01,
            "maximum": 1000000000,
            "default": 500
          },
          "spendCurrency": {
            "title": "Spending currency",
            "type": "string",
            "maxLength": 3,
            "default": "USD"
          },
          "homeCurrency": {
            "title": "Home (account) currency",
            "type": "string",
            "maxLength": 3,
            "default": "EUR"
          },
          "rateSource": {
            "title": "Reference rate",
            "type": "string",
            "enum": [
              "ecb",
              "manual"
            ],
            "default": "ecb"
          },
          "manualRate": {
            "title": "Manual rate: 1 home-currency unit =",
            "description": "…units of the spending currency (e.g. 1 EUR = 1.10 USD → 1.10). Used with \"Enter a rate manually\", or as fallback when the ECB is unreachable.",
            "type": "number",
            "minimum": 0.000001,
            "maximum": 1000000000
          },
          "options": {
            "title": "Payment options",
            "description": "Example values – replace them with your own card’s and provider’s terms. EU card issuers must state their conversion mark-up over the ECB rate.",
            "type": "array",
            "maxItems": 12,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "name": {
                  "title": "Option",
                  "type": "string",
                  "maxLength": 80
                },
                "method": {
                  "title": "Type",
                  "type": "string",
                  "enum": [
                    "card",
                    "atm",
                    "dcc",
                    "exchange"
                  ],
                  "default": "card"
                },
                "feePercent": {
                  "title": "Fee %",
                  "type": "number",
                  "minimum": 0,
                  "maximum": 50,
                  "x-unit": "%"
                },
                "markupPercent": {
                  "title": "Rate mark-up %",
                  "type": "number",
                  "minimum": 0,
                  "maximum": 50,
                  "x-unit": "%"
                },
                "fixedFee": {
                  "title": "Fixed fee (home currency)",
                  "type": "number",
                  "minimum": 0,
                  "maximum": 10000
                }
              },
              "required": []
            },
            "default": [
              {
                "name": "Card without foreign transaction fee",
                "method": "card",
                "feePercent": 0,
                "markupPercent": 0,
                "fixedFee": 0
              },
              {
                "name": "Card with foreign transaction fee",
                "method": "card",
                "feePercent": 1.75,
                "markupPercent": 0,
                "fixedFee": 0
              },
              {
                "name": "ATM cash withdrawal",
                "method": "atm",
                "feePercent": 1,
                "markupPercent": 0,
                "fixedFee": 4
              },
              {
                "name": "\"Pay in your currency\" (DCC) at the terminal",
                "method": "dcc",
                "feePercent": 0,
                "markupPercent": 5,
                "fixedFee": 0
              },
              {
                "name": "Exchange bureau cash",
                "method": "exchange",
                "feePercent": 0,
                "markupPercent": 7,
                "fixedFee": 0
              }
            ]
          },
          "atmWithdrawals": {
            "title": "Number of ATM withdrawals",
            "description": "The fixed fee of ATM options is charged per withdrawal.",
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 1
          }
        },
        "required": [
          "amount",
          "spendCurrency",
          "homeCurrency"
        ]
      },
      "TravelExchangeFeeCalculatorResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "amount",
              "spendCurrency",
              "homeCurrency",
              "referenceRate",
              "referenceCost",
              "rates",
              "options",
              "cheapest",
              "mostExpensive"
            ],
            "properties": {
              "amount": {
                "type": "number"
              },
              "spendCurrency": {
                "type": "string"
              },
              "homeCurrency": {
                "type": "string"
              },
              "referenceRate": {
                "type": "number",
                "description": "Spending-currency units per 1 home-currency unit."
              },
              "referenceCost": {
                "type": "number"
              },
              "rates": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "date",
                  "source",
                  "url",
                  "fetchedAt",
                  "stale"
                ],
                "properties": {
                  "date": {
                    "type": "string",
                    "description": "Reference date of the rates."
                  },
                  "requestedDate": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "source": {
                    "type": "string",
                    "enum": [
                      "ecb-daily",
                      "ecb-sdmx",
                      "manual"
                    ]
                  },
                  "url": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "fetchedAt": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "stale": {
                    "type": "boolean"
                  }
                }
              },
              "options": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "name",
                    "method",
                    "homeCost",
                    "extraCost",
                    "extraPercent",
                    "effectiveRate",
                    "breakdown"
                  ],
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "method": {
                      "type": "string"
                    },
                    "homeCost": {
                      "type": "number"
                    },
                    "extraCost": {
                      "type": "number"
                    },
                    "extraPercent": {
                      "type": "number"
                    },
                    "effectiveRate": {
                      "type": "number"
                    },
                    "breakdown": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "atReference",
                        "markup",
                        "percentFee",
                        "fixedFees"
                      ],
                      "properties": {
                        "atReference": {
                          "type": "number"
                        },
                        "markup": {
                          "type": "number"
                        },
                        "percentFee": {
                          "type": "number"
                        },
                        "fixedFees": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              },
              "cheapest": {
                "type": "string"
              },
              "mostExpensive": {
                "type": "string"
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}