What a REST API Is and Why Finance Teams Should Care
An API (Application Programming Interface) is a contract between two systems. One side says: "Send me a request in this exact format, and I will send back a response in this exact format." That is it. Everything else is detail.
The most common type in financial data work is a REST API. It runs over HTTPS, the same secure protocol your browser uses for most sites, and this matters because financial data APIs will almost always require HTTPS rather than plain HTTP. You make a request to a URL called an endpoint and get back data, almost always in JSON format.
The HTTP methods you will encounter most are:
- GET: retrieve data (fetch an FX rate, pull a position report)
- POST: send data to create something (submit a trade, trigger a calculation)
- PUT: replace an existing record in full
- PATCH: update specific fields of an existing record without replacing the whole thing
- DELETE: remove a record
REST convention distinguishes PUT from PATCH. PUT replaces the full resource; PATCH updates fields selectively. You will encounter both once you start working with TMS or reporting APIs.
Think of it like a formal conversation with your treasury management system. You send a precisely worded request: "Give me the EUR/GBP mid rate as of 09:00 today." The system checks your credentials, finds the data, and hands back a structured response. If your request is malformed or your credentials are wrong, it tells you that too, via a standard HTTP status code. The ones you will see most often are: 200 means success, 401 means unauthenticated or missing credentials, 403 means your credentials are valid but you do not have permission, 404 means not found, and 500 means something broke on the server.
Most financial data that reaches a spreadsheet or report has passed through an API at some point. The question is whether your team controls that step or depends on someone else to run it.
Concrete cases where this matters:
- Pulling live FX rates or benchmark rates into a pricing model without copying from a data terminal
- Connecting a TMS to a reporting layer so positions flow automatically rather than via a daily export and reimport
- Consuming a regulatory data feed (credit ratings, reference data, index compositions) on a schedule
- Exposing an in-house calculation (an FTP curve, a liquidity buffer estimate) so other tools can call it programmatically
The manual copy and paste step is where errors enter. APIs remove that step. Once you understand both sides of the contract, you can design integrations yourself rather than raising a ticket and waiting.
How to Read API Documentation Before Writing Any Code
Good API documentation gives you everything you need before you open a code editor. Look for these five things:
- Base URL: the root address every endpoint is appended to, for example
https://api.example.com/v1 - Authentication method: API key in a header, a bearer token, or OAuth. This tells you how to prove who you are.
- Endpoint paths: the specific routes, such as
/rates/fxor/market/data/rates - Required and optional parameters: query parameters appended to the URL (
?currency=EURGBP&date=2024-01-15) or a JSON body for POST requests - Response schema: the structure of the JSON you get back, including field names, data types, and any nested objects
Read the authentication section first. You cannot test anything until you can make an authenticated request. Read the response schema second, because that tells you what you are actually going to receive and how to parse it.
Many APIs offer a sandbox or test environment with dummy data. Use it. It is far better to make mistakes against a test endpoint than against a live data feed or a production system.
Calling an API in Python
The requests library is the standard tool for this. Install it with pip install requests if it is not already in your environment.
The example below calls a public exchange rate API to fetch a rate. The structure here is representative of most REST API calls you will make in practice.
import requests
import os
# Load your API key from an environment variable, never hardcode it
API_KEY = os.environ.get("FX_API_KEY")
BASE_URL = "https://api.exchangerate.example.com/v1"
def get_fx_rate(base: str, target: str) -> dict:
"""
Fetch the current exchange rate for a currency pair.
base : the base currency code, e.g. 'EUR'
target : the target currency code, e.g. 'GBP'
"""
endpoint = f"{BASE_URL}/latest"
headers = {
"Authorization": f"Bearer {API_KEY}",
"Accept": "application/json"
}
params = {
"base": base,
"symbols": target
}
response = requests.get(endpoint, headers=headers, params=params, timeout=10)
# Raise an exception immediately if the status code signals a problem
response.raise_for_status()
return response.json()
result = get_fx_rate("EUR", "GBP")
print(result)
A weekly note on treasury, liquidity and practical Python. No spam, unsubscribe any time.
A few things worth noting. The timeout=10 argument tells requests to give up after ten seconds rather than hang indefinitely, which matters if you are running this inside a scheduled report. The raise_for_status() call converts a 4xx or 5xx response into a Python exception immediately, so failures are obvious rather than silent.
Parsing the Response Into Something Useful
The JSON response comes back as a Python dictionary. From there you can extract what you need or load it into a pandas DataFrame for further work.
import pandas as pd
def parse_rate_response(response: dict, target: str) -> float:
"""Extract the rate for a single target currency from the response."""
return response["rates"][target]
def rates_to_dataframe(response: dict) -> pd.DataFrame:
"""
Convert the rates section of the response into a tidy DataFrame.
Useful when you request multiple target currencies at once.
"""
rates = response.get("rates", {})
base = response.get("base", "Unknown")
date = response.get("date", "Unknown")
df = pd.DataFrame(
list(rates.items()),
columns=["target_currency", "rate"]
)
df["base_currency"] = base
df["rate_date"] = date
# Reorder columns to match a reporting layout
return df[["rate_date", "base_currency", "target_currency", "rate"]]
df = rates_to_dataframe(result)
print(df)
This gives you a clean DataFrame you can write to a database, export to Excel, or feed straight into a reporting function.
If you are working with numerical operations on the rate column after this point, the post on Python numbers and precision in finance is worth reading before you chain calculations together. And once you start pulling data from multiple sources, when to use NumPy, SciPy, and other numerical libraries covers how to handle it from there.
Building Your Own Simple API with FastAPI: An LCR Example
Understanding what happens on the other side of a request changes how you think about calling one. FastAPI is a Python library that makes building a minimal API straightforward. Install it with pip install fastapi uvicorn.
Suppose your treasury team has a Python function that calculates a liquidity coverage ratio buffer estimate. You want other tools, a dashboard, a reporting script, a colleague's model, to be able to call it without importing your code directly.
The example below uses illustrative HQLA haircuts. For reference, under the LCR framework Level 2A assets carry a 15% haircut (so 85% of face value counts), and Level 2B haircuts vary by asset type: for example, qualifying RMBS and corporate bonds attract different rates under the applicable rules. The 75% figure used for Level 2B in this example is illustrative only and is not the full regulatory schedule. Always refer to the applicable LCR rules (CRR/LCR Delegated Regulation or the relevant local implementation) for submission figures.
from fastapi import FastAPI, Query
from pydantic import BaseModel
app = FastAPI()
# A simple store held in memory, standing in for a real data source
HQLA_HOLDINGS = {
"level1": 80_000_000,
"level2a": 15_000_000,
"level2b": 5_000_000
}
class LCRResponse(BaseModel):
hqla_total: float
net_cash_outflows: float
lcr_ratio: float
indicative_only: bool = True
@app.get("/liquidity/lcr", response_model=LCRResponse)
def calculate_lcr(net_cash_outflows: float = Query(..., description="30-day net cash outflows in base currency")):
"""
Returns an illustrative LCR estimate based on current HQLA holdings.
Haircuts are illustrative only and not a regulatory submission figure.
Level 2A: 15% haircut (85% of face). Level 2B: illustrative 25% haircut (75% of face).
Actual Level 2B haircuts vary by asset type under applicable LCR rules.
"""
# Illustrative haircuts only: see prose note above for regulatory context
hqla = (
HQLA_HOLDINGS["level1"]
+ HQLA_HOLDINGS["level2a"] * 0.85
+ HQLA_HOLDINGS["level2b"] * 0.75
)
lcr = hqla / net_cash_outflows if net_cash_outflows > 0 else 0.0
return LCRResponse(
hqla_total=hqla,
net_cash_outflows=net_cash_outflows,
lcr_ratio=round(lcr, 4)
)
Run it locally with uvicorn main:app --reload and you can immediately call http://127.0.0.1:8000/liquidity/lcr?net_cash_outflows=90000000 from a browser, from requests, or from any other tool. FastAPI also generates interactive documentation at /docs automatically.
This is directly relevant to the pattern described in AI agents in treasury and risk: agents call tools via APIs, so building a small internal API around your calculations is one practical way to make them accessible to automated workflows.
Authentication: Keys, Tokens, and Keeping Credentials Safe
Most financial data APIs use one of these three patterns:
- API key in a header: a static secret sent with every request, typically as
X-API-Key: your_key_here - Bearer token: a token with an expiry, obtained by authenticating first, then sent as
Authorization: Bearer your_token - OAuth 2.0: a more involved flow used by enterprise systems where a user or service account grants scoped access
The rule across all three is the same: never put a credential directly in your code. A script with a hardcoded API key will end up in version control, in a shared folder, or in an email.
Store secrets in environment variables and read them at runtime with os.environ.get(). For local development, a .env file loaded with the python-dotenv package works well. For production or shared infrastructure, use your firm's secret management approach.
import os
from dotenv import load_dotenv
load_dotenv() # Reads from a local .env file if present
API_KEY = os.environ.get("MY_API_KEY")
if not API_KEY:
raise EnvironmentError("MY_API_KEY is not set. Check your environment variables.")
The .env file belongs in .gitignore. That is not optional.
The Practical Takeaway
Start with one workflow that currently involves copying data between systems by hand. Find out whether the source system has an API (most modern platforms do, and the documentation is usually public or available through your vendor contact). Read the authentication section, get a test key, and make one successful GET request in Python. That single working request is the foundation for every integration after it.
You do not need to build a complete data pipeline on the first attempt. A script that pulls one rate, one position, or one report and writes it somewhere useful is already eliminating manual effort and the errors that come with it.
If you want to go further with Python for finance work, the Academy catalogue has structured courses covering Python, treasury, and analytics together. The learning paths are worth looking at if you want a guided progression rather than individual topics.

The Complete Python Course
Welcome to the most practical and beginner friendly Python Bootcamp Course on YouTube.
Take the courseGet the next one in your inbox
A weekly note across Finance & Treasury, Innovation & Automation and Career Development. No spam, unsubscribe any time.
Notes across finance and treasury, innovation and automation, and career development, written by practitioners who do the work.
