β‘ Async Python client for the Firi cryptocurrency exchange API.
pip install firipyRequires Python 3.13+.
All methods are async and must be awaited:
import asyncio
from firipy import FiriAPI
async def main():
async with FiriAPI("your-api-key") as client:
time = await client.time()
print(time)
markets = await client.markets()
print(markets)
balances = await client.balances()
print(balances)
asyncio.run(main())Built-in client-side pacing (seconds to sleep before each request). Default is 1 second:
client = FiriAPI("your-api-key", rate_limit=2) # 2 second delay
client = FiriAPI("your-api-key", rate_limit=0) # no delayUses asyncio.sleep so it won't block the event loop.
Structured exceptions are raised by default:
| Exception | Description |
|---|---|
FiriAPIError |
Base class for client errors |
FiriHTTPError |
Non-success HTTP responses (status >= 400) |
Suppress exceptions with raise_on_error=False:
async with FiriAPI("your-api-key", raise_on_error=False) as client:
data = await client.markets()
if isinstance(data, dict) and "error" in data:
print("Failed:", data)Error dict shape: {"error": str, "status": int | None}.
| Method | Endpoint | Purpose | Key Optional Params |
|---|---|---|---|
time() |
/time |
Server time | -- |
markets() |
/v2/markets |
List markets | -- |
markets_market(m) |
/v2/markets/{m} |
Market details | -- |
markets_market_depth(m, bids=, asks=) |
/v2/markets/{m}/depth |
Order book | bids, asks |
markets_market_history(m, count=) |
/v2/markets/{m}/history |
Market trade history | count |
markets_market_ticker(m) |
/v2/markets/{m}/ticker |
Single ticker | -- |
markets_tickers() |
/v2/markets/tickers |
All tickers | -- |
balances() |
/v2/balances |
Wallet balances | -- |
history_transactions(count=, direction=) |
/v2/history/transactions |
Transaction history | count, direction |
history_transactions_year(year, direction=) |
/v2/history/transactions/{year} |
Yearly transactions | direction |
history_transactions_month_year(month, year, direction=) |
/v2/history/transactions/{month}/{year} |
Monthly transactions | direction |
history_orders(type=, count=) |
/v2/history/orders |
Order history | type, count |
history_orders_market(m, type=, count=) |
/v2/history/orders/{m} |
Market order history | type, count |
deposit_history(count=, before=) |
/v2/deposit/history |
Deposit history | count, before |
deposit_address() |
/v2/deposit/address |
Multi-coin deposit info | -- |
orders() |
/v2/orders |
Active orders | -- |
orders_market(m, count=) |
/v2/orders/{m} |
Active orders (market) | count |
orders_market_history(m, count=) |
/v2/orders/{m}/history |
Closed orders (market) | count |
orders_history(count=) |
/v2/orders/history |
Closed orders | count |
order(order_id) |
/v2/order/{id} |
Get order | -- |
post_orders(market, type, price, amount) |
/v2/orders |
Create order | -- |
delete_orders() |
/v2/orders |
Cancel all orders | -- |
delete_orders_for_market(market) |
/v2/orders/{market} |
Cancel market orders | -- |
delete_order_detailed(order_id, market=) |
/v2/orders/{id}/detailed |
Cancel + matched amt | market |
coin_address(symbol) |
/v2/{symbol}/address |
Coin deposit address | -- |
coin_withdraw_pending(symbol) |
/v2/{symbol}/withdraw/pending |
Pending withdrawals | -- |
Default count is 500 (DEFAULT_COUNT). A warning is emitted above MAX_COUNT (10,000).
Instead of btc_address(), eth_address(), etc. you can use:
await client.coin_address("BTC")
await client.coin_withdraw_pending("ETH")Per-asset convenience methods remain available.
- Checked against developers.firi.com (Trading API 1.0.0) on 2025-11-21.
- When Firi updates their spec, diff it against the endpoint table above.
- Use the rate-limit guardrails (
DEFAULT_COUNT,MAX_COUNT) to stay within API constraints.
Contributions welcome! Submit a pull request or create an issue on the GitHub page.
git clone https://github.com/jeircul/firipy
cd firipy
uv sync
uv run pytest -qLinting and type checking:
uv run ruff check .
uv run ruff format --check .
uv run ty checkIf you have go-task installed:
task install # uv sync
task lint # ruff check
task format # ruff format
task typecheck # ty check
task test # pytest
task qa # lint + typecheck + test
task balance # print live balances (API_KEY_FIRI required)
task live-test # read-only smoke against production (LIVE_FIRI_TESTS=1)
task build # uv build (sdist + wheel)
task release-check # qa + build
# Version bump helpers (patch by default)
task version PART=minor
task version NEW=1.1.0
task version DRY_RUN=1- Document all changes under the
[Unreleased]section inCHANGELOG.md. - Run
task version PART=major|minor|patch(orNEW=x.y.z). This updatespyproject.tomland moves changelog entries into a dated section. Preview first withDRY_RUN=1. - Run
task release-checkto verify lint, type-check, tests, and build all pass. - Commit the version bump, push to a feature branch, open a PR into
main, and merge once CI is green. - Tag
vX.Y.Zonmain(or draft a GitHub Release). Publishing the release triggerspublish.ymlwhich uploads to PyPI. - Optionally run
LIVE_FIRI_TESTS=1 task live-testbefore tagging to smoke-test against production. - Quick manual check:
task balanceprints balances from/v2/balances.
v1.0.0 is async-only and uses httpx instead of requests. See the CHANGELOG for a full migration guide.
This client was developed by Ove Aursland and is not officially associated with Firi.