Skip to main content

folioman-client

PyPI version Python versions License: MIT Documentation

Official typed asynchronous Python SDK for the Folioman REST API.

The folioman-client library provides an asynchronous, strongly typed interface for interacting with Folioman services. It handles HTTP communication, JWT authentication lifecycles, proactive and reactive token refresh, concurrent locking, and response mapping into Pydantic models.


Key Features

  • Asynchronous Transport: Built on top of httpx.AsyncClient with native HTTP/2 and connection pooling.
  • Automated JWT Lifecycle: Obtains initial tokens from /api/auth/token/pair, automatically refreshes via /api/auth/token/refresh, and transparently retries requests on HTTP 401.
  • Concurrency-Safe Token Refresh: Utilizes an internal asyncio.Lock to guarantee that only one concurrent refresh request runs at any time.
  • Proactive Expiry Absorption: Evaluates token expiry using an embedded payload decoder and proactively refreshes 30 seconds before actual token expiration (EXP_SKEW_SECONDS = 30).
  • Typed Response Parsing: Parses JSON payloads into Pydantic v2 models that handle Decimal serializations and ignore unknown extra attributes for forward-compatibility.
  • Structured Exception Hierarchy: Maps HTTP status codes into specific client exceptions (FoliomanAuthError, FoliomanNotFoundError, FoliomanAPIError).

Prerequisites

This client depends on a running instance of the Folioman service:

  • A running Folioman backend server (default URL: http://localhost:8000, or configured via FOLIOMAN_BASE_URL / base_url).
  • Valid advisor / user credentials (username and password) configured on the Folioman service.

Installation

pip install folioman-client

Or using uv:

uv add folioman-client

Quickstart

It is strongly recommended to use FoliomanClient as an asynchronous context manager:

import asyncio
from folioman_client import FoliomanClient


async def main() -> None:
    # Uses FOLIOMAN_BASE_URL, FOLIOMAN_USERNAME, FOLIOMAN_PASSWORD from environment
    async with FoliomanClient.from_env() as client:
        # Fetch accessible investors
        investors = await client.investors.list()
        for investor in investors:
            print(f"Investor: {investor.name} (ID: {investor.id})")

            # Fetch portfolio summary
            summary = await client.portfolio.get(investor.id)
            print(f"  Total Portfolio Value: INR {summary.total_inr:,.2f}")
            print(f"  XIRR: {summary.xirr * 100:.2f}%" if summary.xirr else "  XIRR: N/A")


if __name__ == "__main__":
    asyncio.run(main())

Client Initialization

The client can be instantiated in three ways:

1. From Environment Variables (from_env)

Automatically loads configuration from environment variables or .env file using the FOLIOMAN_ prefix:

from folioman_client import FoliomanClient

client = FoliomanClient.from_env()

Supported environment variables:

  • FOLIOMAN_BASE_URL: API service endpoint (default: http://localhost:8000)
  • FOLIOMAN_USERNAME: Advisor username
  • FOLIOMAN_PASSWORD: Advisor password
  • FOLIOMAN_TIMEOUT: Request timeout in seconds (default: 30.0)

2. Directly with Arguments

from folioman_client import FoliomanClient

client = FoliomanClient(
    base_url="http://localhost:8000",
    username="advisor",
    password="supersecretpassword",
    timeout=30.0,
)

3. From a FoliomanSettings Instance

from folioman_client import FoliomanClient, FoliomanSettings

settings = FoliomanSettings(
    base_url="http://localhost:8000",
    username="advisor",
    password="supersecretpassword",
)
client = FoliomanClient.from_settings(settings)

Resource Sub-Clients

FoliomanClient exposes its API through organized resource sub-clients:

Resource Methods Description
client.investors list(), get(investor_id) Query advisor-accessible investors and detailed profiles with masked PAN.
client.portfolio get(investor_id, as_of=None) Query aggregated portfolio summaries, metrics, XIRR, and asset mix.
client.holdings list(investor_id), get(investor_id, security_id) Query priced holdings, folio breakdown, historical NAV points, and transactions.
client.transactions list(investor_id) Access raw transaction ledger records (buys, sells, switches, dividends).
client.valuations list(investor_id), status(investor_id) Reconstruct historical net-worth time series and check calculation readiness.
client.capital_gains list(investor_id), get(investor_id, fy=...) Generate realized STCG/LTCG capital gains reports across financial years.

Error Handling

All client exceptions derive from FoliomanError:

from folioman_client import (
    FoliomanClient,
    FoliomanAuthError,
    FoliomanNotFoundError,
    FoliomanAPIError,
)

async with FoliomanClient.from_env() as client:
    try:
        investor = await client.investors.get(99999)
    except FoliomanNotFoundError:
        print("Investor does not exist.")
    except FoliomanAuthError as exc:
        print(f"Authentication failed: {exc}")
    except FoliomanAPIError as exc:
        print(f"Status Code: {exc.status_code}")
        print(f"Error Details: {exc.response_data}")

Documentation

Full documentation is available at: https://sid-146.github.io/folioman-client/

To build documentation locally:

uv sync --group dev
uv run mkdocs serve

License

This project is licensed under the MIT License - see the LICENSE file for details.

Release files for folioman-client 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for folioman-client 0.1.0
File Size Uploaded
folioman_client-0.1.0.tar.gz 103.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for folioman-client 0.1.0
File Interpreter ABI Platform
folioman_client-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 122.8 kB

Release files / folioman_client-0.1.0.tar.gz

Download URL folioman_client-0.1.0.tar.gz
Size 103.7 kB
Tags Source
SHA-256 checksum
How to use checksums
df7151a6d39114d950552765f0870eab2c16bde0f5baa0b8650fa987d3abfcf0
BLAKE2b-256 checksum
How to use checksums
5a80a6d1f23b939a54af5780eab37134ef1e3583b58c8891b556ab34cb575cd2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 25, 2026.

Transparency log

Release files / folioman_client-0.1.0-py3-none-any.whl

Download URL folioman_client-0.1.0-py3-none-any.whl
Size 19.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
953e500b585e55326dee24d123be1a799da1902866c484f0ddf75f34ccae596e
BLAKE2b-256 checksum
How to use checksums
281d13b4637b527273779e28882317c673e9a4001990e012f8dc77ce8aa40354
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 25, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page