Skip to content

Commit 9d04cef

Browse files
cahthuranagclaude
andcommitted
Initial release v1.0.0
Exchange Rate API SDK — real-time mid-market currency exchange rates for 160+ currencies. Rebranded for exchange-rateapi.com. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0 parents  commit 9d04cef

7 files changed

Lines changed: 830 additions & 0 deletions

File tree

.github/workflows/publish.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Publish to PyPI
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
publish:
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- name: Set up Python
18+
uses: actions/setup-python@v5
19+
with:
20+
python-version: "3.12"
21+
22+
- name: Install build dependencies
23+
run: pip install build twine
24+
25+
- name: Build package
26+
run: python -m build
27+
28+
- name: Publish to PyPI
29+
env:
30+
TWINE_USERNAME: __token__
31+
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
32+
run: twine upload dist/*

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
__pycache__/
2+
dist/
3+
*.egg-info/
4+
.venv/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025-2026 Exchange Rate API
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
# exchangerateapi
2+
3+
[![PyPI version](https://img.shields.io/pypi/v/exchangerateapi.svg)](https://pypi.org/project/exchangerateapi/)
4+
[![license](https://img.shields.io/pypi/l/exchangerateapi.svg)](https://github.com/Exchange-RateAPI/exchange-rateapi-python/blob/main/LICENSE)
5+
[![Python](https://img.shields.io/pypi/pyversions/exchangerateapi.svg)](https://pypi.org/project/exchangerateapi/)
6+
[![zero dependencies](https://img.shields.io/badge/dependencies-0-brightgreen.svg)](https://pypi.org/project/exchangerateapi/)
7+
8+
**The most elegant way to access real-time mid-market exchange rates in Python**
9+
10+
## Why Choose This Client?
11+
12+
- **Lightning Fast** -- Zero dependencies, pure Python standard library
13+
- **Real-Time Data** -- Rates updated every 60 seconds from Reuters (Refinitiv) and interbank feeds
14+
- **Mid-Market Rates** -- The true interbank rate -- no hidden spread or markup
15+
- **160+ Currencies** -- Major, minor, and exotic currency pairs
16+
- **Type Hints** -- Full type annotations for IDE autocomplete
17+
- **Zero Dependencies** -- Uses only `urllib` and `json` from the standard library
18+
19+
## Get Your API Key
20+
21+
Ready to start? Get your free API key from [exchange-rateapi.com/register](https://exchange-rateapi.com/register).
22+
23+
## Installation
24+
25+
```bash
26+
pip install exchangerateapi
27+
```
28+
29+
## Quick Start
30+
31+
Get up and running in seconds:
32+
33+
```python
34+
from exchangerateapi import ExchangeRateAPI
35+
36+
# Set your API key
37+
client = ExchangeRateAPI(api_key="era_live_YOUR_API_KEY")
38+
39+
# Get latest exchange rates
40+
data = client.latest(base="USD", symbols=["EUR", "GBP", "JPY"])
41+
print(data["rates"]) # {"EUR": 0.9234, "GBP": 0.7891, "JPY": 151.42}
42+
43+
# Convert an amount
44+
result = client.convert("USD", "EUR", 1000)
45+
print(f"$1,000 = EUR {result['result']}")
46+
```
47+
48+
## API Reference
49+
50+
- [Latest Rates](#latest-exchange-rates) -- Get current exchange rates
51+
- [Historical Data](#historical-exchange-rates) -- Fetch rates for specific dates
52+
- [Currency Conversion](#currency-conversion) -- Convert between currencies
53+
- [Time Series](#time-series-data) -- Get rates over date ranges
54+
- [Available Currencies](#available-currencies) -- List all supported currencies
55+
- [Single Rate](#single-rate) -- Get one currency pair
56+
- [Historical by Period](#historical-rates-by-period) -- Preset period lookups
57+
58+
---
59+
60+
### Latest Exchange Rates
61+
62+
Get the most current exchange rates with a single call:
63+
64+
```python
65+
# All rates from USD (default base)
66+
data = client.latest()
67+
print(data["rates"])
68+
69+
# Target specific currencies with EUR base
70+
data = client.latest(base="EUR", symbols=["USD", "GBP", "JPY"])
71+
print(data["rates"])
72+
# {"USD": 1.083, "GBP": 0.8546, "JPY": 163.92}
73+
```
74+
75+
**Response:**
76+
77+
```python
78+
{
79+
"base": "EUR",
80+
"date": "2026-04-09T14:30:00Z",
81+
"rates": {"USD": 1.083, "GBP": 0.8546, "JPY": 163.92}
82+
}
83+
```
84+
85+
---
86+
87+
### Historical Exchange Rates
88+
89+
Travel back in time to get rates from any date:
90+
91+
```python
92+
# Using a string date
93+
data = client.for_date("2026-01-15", base="USD", symbols=["EUR"])
94+
print(data["rates"]) # {"EUR": 0.9187}
95+
96+
# Using a date object
97+
from datetime import date
98+
data = client.for_date(date(2026, 1, 15), base="EUR", symbols=["USD", "GBP"])
99+
100+
# Using a datetime object
101+
from datetime import datetime
102+
data = client.for_date(datetime(2026, 1, 15, 12, 0, 0))
103+
```
104+
105+
**Response:**
106+
107+
```python
108+
{
109+
"base": "USD",
110+
"date": "2026-01-15",
111+
"rates": {"EUR": 0.9187}
112+
}
113+
```
114+
115+
---
116+
117+
### Currency Conversion
118+
119+
Convert any amount between currencies -- including historical conversions:
120+
121+
```python
122+
# Current conversion
123+
result = client.convert("USD", "EUR", 1000)
124+
print(result)
125+
# {"from": "USD", "to": "EUR", "amount": 1000, "result": 923.4, "rate": 0.9234}
126+
127+
# Historical conversion -- what was $1,000 worth on Jan 15?
128+
result = client.convert("USD", "EUR", 1000, date="2026-01-15")
129+
print(f"Rate on Jan 15: {result['rate']}")
130+
# {"from": "USD", "to": "EUR", "amount": 1000, "result": 918.7, "rate": 0.9187, "date": "2026-01-15"}
131+
132+
# Using a date object
133+
from datetime import date
134+
result = client.convert("GBP", "JPY", 500, date=date(2025, 12, 31))
135+
```
136+
137+
---
138+
139+
### Available Currencies
140+
141+
Discover all 160+ supported currency symbols and names:
142+
143+
```python
144+
data = client.symbols()
145+
print(data["symbols"])
146+
# {
147+
# "USD": "United States Dollar",
148+
# "EUR": "Euro",
149+
# "GBP": "British Pound Sterling",
150+
# "JPY": "Japanese Yen",
151+
# ...160+ currencies
152+
# }
153+
154+
# Build a currency list
155+
for code, name in data["symbols"].items():
156+
print(f"{code}: {name}")
157+
```
158+
159+
---
160+
161+
### Time Series Data
162+
163+
Get exchange rates over a date range for trend analysis and charting:
164+
165+
```python
166+
data = client.time_series(
167+
"2026-01-01", "2026-03-31",
168+
base="USD",
169+
symbols=["EUR", "GBP"],
170+
)
171+
print(data["rates"]["2026-01-15"])
172+
# {"EUR": 0.9187, "GBP": 0.7834}
173+
174+
# Using date objects
175+
from datetime import date
176+
data = client.time_series(
177+
date(2026, 1, 1), date(2026, 3, 31),
178+
symbols=["EUR"],
179+
)
180+
```
181+
182+
**Response:**
183+
184+
```python
185+
{
186+
"base": "USD",
187+
"start_date": "2026-01-01",
188+
"end_date": "2026-03-31",
189+
"rates": {
190+
"2026-01-01": {"EUR": 0.9187, "GBP": 0.7834},
191+
"2026-01-02": {"EUR": 0.9195, "GBP": 0.7841},
192+
...
193+
}
194+
}
195+
```
196+
197+
---
198+
199+
### Single Rate
200+
201+
Get a single exchange rate between two currencies:
202+
203+
```python
204+
rate = client.get_rate("USD", "EUR")
205+
print(f"1 USD = {rate['rate']} EUR")
206+
207+
# With amount
208+
rate = client.get_rate("USD", "EUR", 500)
209+
print(f"$500 = EUR {rate['to']['amount']}")
210+
```
211+
212+
---
213+
214+
### Historical Rates by Period
215+
216+
Get historical rates using preset periods -- no date math needed:
217+
218+
```python
219+
history = client.get_historical_rates("USD", "EUR", "30d")
220+
print(f"Current: {history['current']['rate']}")
221+
for point in history["rates"]:
222+
print(f"{point['time']}: {point['rate']}")
223+
```
224+
225+
**Available periods:** `1d`, `7d`, `30d`, `1y` (default: `7d`)
226+
227+
---
228+
229+
## Configuration
230+
231+
```python
232+
client = ExchangeRateAPI(
233+
api_key="era_live_YOUR_API_KEY", # Required
234+
base_url="https://exchange-rateapi.com", # Optional
235+
timeout=10, # Optional (seconds)
236+
)
237+
```
238+
239+
| Parameter | Type | Default | Description |
240+
| ---------- | ----- | ------------------------------ | ------------------------------- |
241+
| `api_key` | `str` | -- | Your API key |
242+
| `base_url` | `str` | `https://exchange-rateapi.com` | API base URL |
243+
| `timeout` | `int` | `10` | Request timeout in seconds |
244+
245+
---
246+
247+
## Per-Request API Key Override
248+
249+
Every method supports a per-request API key override -- useful for multi-tenant apps:
250+
251+
```python
252+
client = ExchangeRateAPI(api_key="default_key")
253+
254+
# Override for a specific request
255+
data = client.latest(api_key="other_users_key")
256+
result = client.convert("USD", "EUR", 100, api_key="tenant_key")
257+
symbols = client.symbols(api_key="another_key")
258+
```
259+
260+
---
261+
262+
## Error Handling
263+
264+
All errors are raised as `ExchangeRateAPIError` with an optional HTTP status code:
265+
266+
```python
267+
from exchangerateapi import ExchangeRateAPI, ExchangeRateAPIError
268+
269+
client = ExchangeRateAPI(api_key="era_live_YOUR_API_KEY")
270+
271+
try:
272+
rate = client.get_rate("USD", "INVALID")
273+
except ExchangeRateAPIError as e:
274+
print(e) # "Currency not found"
275+
print(e.status) # 404
276+
```
277+
278+
| Status | Meaning |
279+
| ------ | -------------------------------------- |
280+
| -- | Missing API key (raised before request) |
281+
| `401` | Invalid API key |
282+
| `404` | Currency code not found |
283+
| `429` | Rate limit exceeded |
284+
| `500` | Server error |
285+
286+
---
287+
288+
## Methods Reference
289+
290+
| Method | Description |
291+
| --------------------------------------------------- | ---------------------------------------------------------- |
292+
| `latest(base, symbols, api_key)` | Get latest rates for one or more currencies |
293+
| `for_date(date, base, symbols, api_key)` | Get rates for a specific historical date |
294+
| `convert(from, to, amount, date, api_key)` | Convert amount (supports historical date) |
295+
| `time_series(start, end, base, symbols, api_key)` | Get rates across a custom date range |
296+
| `symbols(api_key)` | List all 160+ supported currency codes and names |
297+
| `get_rate(from, to, amount, api_key)` | Get a single exchange rate |
298+
| `get_rates(source, target, api_key)` | Get rates with full metadata |
299+
| `get_historical_rates(source, target, period, api_key)` | Historical rates by preset period (1d/7d/30d/1y) |
300+
301+
---
302+
303+
## Zero Dependencies
304+
305+
This SDK uses only Python standard library (`urllib`, `json`). No external packages required. Nothing to audit, nothing to break.
306+
307+
---
308+
309+
## Links
310+
311+
- [API Documentation](https://exchange-rateapi.com/developers)
312+
- [Register (Free)](https://exchange-rateapi.com/register)
313+
- [Dashboard](https://exchange-rateapi.com/profile)
314+
- [Status](https://exchange-rateapi.com/status)
315+
- [GitHub](https://github.com/Exchange-RateAPI/exchange-rateapi-python)
316+
317+
## License
318+
319+
MIT

0 commit comments

Comments
 (0)