Folioman Client¶
Typed asynchronous Python SDK for the Folioman REST API.
The folioman-client library provides a high-performance, asynchronous, and strictly typed interface for financial advisors, wealth management platforms, and algorithmic systems to interact with Folioman services.
Service Dependency
This client library depends on a running instance of the Folioman backend service. Ensure your Folioman API server is running and accessible (by default at http://localhost:8000, or configured via base_url / FOLIOMAN_BASE_URL) before connecting.
Key Features¶
- Asynchronous Transport: Built on
httpx.AsyncClientwith native HTTP/2 support, connection pooling, and configurable timeouts. - Automated JWT Lifecycle: Acquires tokens from
/api/auth/token/pair, refreshes automatically via/api/auth/token/refresh, and transparently retries requests on HTTP 401. - Concurrency-Safe Renewal: Coordinates concurrent token refresh operations using an
asyncio.Lockto guarantee single-flight renewal. - Proactive Expiry Absorption: Parses JWT expiry directly without third-party dependencies and refreshes tokens 30 seconds prior to expiration (
EXP_SKEW_SECONDS = 30). - Pydantic v2 Models: Deserializes responses into strongly typed models with automatic
Decimalanddate/datetimeserialization handling. - Granular Error Handling: Maps HTTP status codes into intuitive exception classes (
FoliomanAuthError,FoliomanNotFoundError,FoliomanAPIError).
Supported Python Versions¶
folioman-client requires Python 3.11 or newer (tested on Python 3.11, 3.12, 3.13, and 3.14).
Installation¶
Install using standard Python package managers:
Minimal Example¶
import asyncio
from folioman_client import FoliomanClient
async def main() -> None:
# Connect using environment variables or direct arguments
async with FoliomanClient(
base_url="http://localhost:8000",
username="advisor",
password="securepassword",
) as client:
# Fetch list of accessible investors
investors = await client.investors.list()
for investor in investors:
print(f"Investor ID: {investor.id} | Name: {investor.name}")
# Fetch investor portfolio summary
portfolio = await client.portfolio.get(investor.id)
print(f" Total Portfolio Value: INR {portfolio.total_inr:,.2f}")
print(f" Holdings Count: {len(portfolio.holdings)}")
if __name__ == "__main__":
asyncio.run(main())
Architecture Overview¶
graph TD
App[User Application] --> Client[FoliomanClient]
Client --> Auth[JWTAuthManager]
Client --> ResInv[client.investors]
Client --> ResPort[client.portfolio]
Client --> ResHold[client.holdings]
Client --> ResTxn[client.transactions]
Client --> ResVal[client.valuations]
Client --> ResCG[client.capital_gains]
ResInv --> Transport[HTTP Transport / httpx]
ResPort --> Transport
ResHold --> Transport
ResTxn --> Transport
ResVal --> Transport
ResCG --> Transport
Transport --> FoliomanAPI[Folioman REST API]
Auth --> |Injects / Refreshes Bearer Token| Transport
Navigation & Guides¶
- Getting Started: Installation, client lifecycle, and first API requests.
- Configuration: Environment variables,
.envfiles, andFoliomanSettings. - Authentication: JWT flows, refresh locks, and proactive expiry absorption.
- Client API: Deep-dive into all client resources and methods.
- Models: Complete reference of Pydantic response models and custom types.
- Errors: Exception hierarchy and robust error handling patterns.
- Examples: Practical end-to-end recipes.
- API Reference: Automatically generated API documentation from source code.
- Development: Contributing, testing, and building the package.
- GitHub Repository: Issues, source code, and release notes.