Unofficial Python SDK for elTOQUE exchange-rate data. A modern, typed client for the official elTOQUE exchange-rate API, with sync and async interfaces.
Independent project.
eltoque-pythonis community-maintained. It is not developed, sponsored, endorsed or supported by elTOQUE.Exchange rates are indicative, not official. Source: elTOQUE. Access requires registration and an application-specific API token.
import os
from eltoque import ElToqueClient
with ElToqueClient(api_token=os.environ["ELTOQUE_API_TOKEN"]) as client:
response = client.get_latest_rates()
print(response.data) # the provider's JSON, untouched
Leer en español: docs/quickstart.es.md
Why use it?
- Sync and async clients with the same methods and behavior.
- Typed public API (
py.typed, checked withmypy --strict). - Safe by default: HTTPS only, explicit timeouts, no redirects followed (your token is never
forwarded to another host), bounded response size, and the token never appears in
repr, error messages or logs. - Predictable errors: one exception family, one subclass per documented HTTP status.
- Rate-limit aware: parses
X-RateLimit-*andRetry-After; retries are opt-in and bounded. - Pure Python, one runtime dependency (
httpx), works in plain scripts, notebooks, Django, Flask, FastAPI or AWS Lambda. - Tested offline with mocked HTTP: no token needed to develop or run the test suite.
Installation
pip install eltoque-python
Requires Python 3.11 or newer. To work on the SDK itself, install from a clone with pip install -e ..
Get your API token
The SDK does not grant API access. Each application that integrates the API needs its own token, requested from elTOQUE:
- Fill in the official form: https://tasas-token.eltoque.com/
- Read the terms of use.
- Keep the token secret and read it from the environment:
export ELTOQUE_API_TOKEN="your-application-token"
Never commit a token, share it with third parties, or ship it in a browser bundle.
Quickstart
Latest rates (rolling last 24 hours)
import os
from eltoque import ElToqueClient
with ElToqueClient(api_token=os.environ["ELTOQUE_API_TOKEN"]) as client:
response = client.get_latest_rates()
print(response.data)
A specific window (shorter than 24 hours)
import os
from datetime import datetime
from eltoque import ElToqueClient
with ElToqueClient(api_token=os.environ["ELTOQUE_API_TOKEN"]) as client:
response = client.get_rates(
datetime(2022, 10, 27, 0, 0, 0),
datetime(2022, 10, 27, 23, 59, 59),
)
print(response.data)
Async
import asyncio
import os
from eltoque import AsyncElToqueClient
async def main() -> None:
async with AsyncElToqueClient(api_token=os.environ["ELTOQUE_API_TOKEN"]) as client:
response = await client.get_latest_rates()
print(response.data)
asyncio.run(main())
Handling errors
import os
from eltoque import ElToqueClient, ElToqueError, ElToqueRateLimitError
with ElToqueClient(api_token=os.environ["ELTOQUE_API_TOKEN"], max_retries=2) as client:
try:
response = client.get_latest_rates()
except ElToqueRateLimitError as error:
print(f"Rate limited, retry in {error.retry_after} s")
except ElToqueError as error:
print(f"Request failed: {error}")
else:
print(response.rate_limit.remaining, "requests left in this window")
API reference
Clients
ElToqueClient (sync) and AsyncElToqueClient (async, await every method) share this
constructor:
| Parameter | Default | Description |
|---|---|---|
api_token |
required | Your application token. Printable ASCII, no spaces, no Bearer prefix. |
base_url |
https://tasas.eltoque.com |
HTTPS only. Plain http:// is accepted for localhost/loopback (tests). |
timeout |
10 s (5 s connect) |
Seconds, or an httpx.Timeout. |
max_retries |
0 |
Opt-in retries (max 5). See Rate limits. |
transport |
None |
Test seam, e.g. httpx.MockTransport. |
http_client |
None |
Your own httpx.Client / httpx.AsyncClient. It is never closed by the SDK, and its own timeout applies. |
| Method | Description |
|---|---|
get_latest_rates() |
Rolling last 24 hours, computed by the provider at request time. |
get_rates(date_from, date_to) |
Explicit window, strictly shorter than 24 hours. |
get_rates_for_day(day) |
day 00:00:00 to day 23:59:59. One request. |
close() / aclose() |
Release connections. Idempotent. Also called by with / async with. |
Using a client after it was closed raises ElToqueError.
RatesResponse
| Attribute | Description |
|---|---|
data |
The decoded JSON body, exactly as the provider sent it (object, list, scalar or null). |
status_code |
HTTP status (SDK metadata). |
rate_limit |
RateLimitInfo with optional limit, remaining, reset, retry_after (SDK metadata). |
received_at |
UTC timestamp of when the SDK received the response (SDK metadata). |
Exceptions
ElToqueError
├── ElToqueConfigurationError invalid token, base_url, timeout, retries
├── ElToqueValidationError invalid arguments, detected before any request
├── ElToqueNetworkError connection, DNS, TLS, protocol failures
├── ElToqueTimeoutError
├── ElToqueDecodeError 200 response that is not valid JSON, or too large
└── ElToqueAPIError has .status_code, .body_excerpt, .rate_limit, .retry_after
├── ElToqueBadRequestError 400
├── ElToqueAuthenticationError 401
├── ElToqueUnprocessableError 422
├── ElToqueRateLimitError 429
└── ElToqueServerError 5xx
Other 3xx/4xx statuses raise the base ElToqueAPIError. See docs/errors.md.
Date and time rules
date_fromanddate_tomust be naivedatetimeobjects. Timezone-aware values are rejected, because the API does not document its time zone and the SDK will not guess one.- They are sent as
YYYY-MM-DD HH:MM:SS(microseconds are dropped). date_frommust be earlier thandate_to, and the window must be shorter than 24 hours, otherwise the API answers HTTP 400. The SDK rejects invalid windows before any request.get_rates_for_dayis a convenience; it is not guaranteed to be a complete local calendar day.
Rate limits and retries
By default each API key may make 60 requests/minute and up to 10 requests/second; your key
may have different limits. Over the limit the API answers 429 with a Retry-After header.
- Retries are off (
max_retries=0). Every retry consumes quota. - With
max_retries > 0the SDK retries only429,502,503,504and transport failures, never400,401or422. Retry-Afteris honored. If the server asks for longer than 30 s (or the 60 s total budget), the error is raised instead of waiting.- There is no background polling, caching or bulk collection. You decide when to call.
Known limitations
- Only one operation is documented by the provider:
GET /v1/trmi. That is all this SDK calls. - The provider does not publish the schema of a successful response, so
RatesResponse.datais untyped and no field (currency names, timestamps, ...) is guaranteed. Typed rate models will come only after the schema is validated with authorized access. - The time zone of the API is undocumented (see above).
- Installing this SDK does not give you access to the API; you need your own approved token.
Supported Python versions
Python 3.11, 3.12, 3.13 and 3.14. No framework is required.
Development
uv sync # or: pip install -e . && pip install pytest pytest-asyncio pytest-cov ruff mypy build twine
uv run ruff check .
uv run ruff format --check .
uv run mypy src
uv run pytest # offline, no token needed
uv run python -m build
uv run twine check dist/*
Optional live check, only with your own authorized token (never run in CI). One request; the script prints the response shape, never provider values. See docs/live-testing.md:
ELTOQUE_API_TOKEN=... ELTOQUE_ALLOW_LIVE_TESTS=1 python scripts/live_check.py
Security and legal
- Treat your token like a password. See docs/security.md.
- This project is not affiliated with elTOQUE. When you display rates, name elTOQUE as the source and describe them as reference estimates, as the terms of use require. Do not modify the data, share your key, resell the data or mass-extract it.
- The MIT license covers this SDK's source code only. It grants no rights over elTOQUE's API, data, name or trademarks.
Official resources
- API landing page: https://tasas.eltoque.com/
- Interactive docs: https://tasas.eltoque.com/docs/
- OpenAPI document: https://tasas.eltoque.com/static/swagger.json
- What is and is not verified: docs/api-contract.md
Community
- Contributing guide: CONTRIBUTING.md
- Code of conduct: CODE_OF_CONDUCT.md
- Security policy: SECURITY.md
- Release notes: CHANGELOG.md
Metadata
Release files for eltoque-python 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| eltoque_python-0.1.1.tar.gz | 36.5 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| eltoque_python-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 56.2 kB
Release files / eltoque_python-0.1.1.tar.gz
| Download URL | eltoque_python-0.1.1.tar.gz |
|---|---|
| Size | 36.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f99892455d8c59e901a4eefaaa30f01e35f984be2e63b68e0497d1693333d505
|
|
BLAKE2b-256 checksum How to use checksums |
0cdd89265c80fd66d4b44d3c40580df05b28c39f79234ed7a3ec114b0afa52ca
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.
Transparency logRelease files / eltoque_python-0.1.1-py3-none-any.whl
| Download URL | eltoque_python-0.1.1-py3-none-any.whl |
|---|---|
| Size | 19.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f1b22d566a1d0aeebbd083dd09d68be27df8cd924f87cb33670e2361552dffc1
|
|
BLAKE2b-256 checksum How to use checksums |
8d3bf8a1fc13e917da27ba85bf52693c0835bf199a9cd0d0eb06ee203f6d6394
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.
Transparency logSecurity for eltoque-python 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for eltoque_python-0.1.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 23, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.