### Install Nordigen Account Library Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/README.md Install the library using pip. This is the first step before using the library. ```bash pip install nordigen_account ``` -------------------------------- ### Install Project Dependencies Source: https://github.com/rahulpdev/nordigen_account/blob/main/README.md Install all required Python packages listed in the requirements.txt file using pip. ```bash pip install -r requirements.txt ``` -------------------------------- ### Create Nordigen Client and Manage Accounts Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/00_START_HERE.txt This example demonstrates how to create a Nordigen client using your secret ID and key, and then use a BankAccountManager to iterate through accounts, update their data and balances, and print account details. It requires the `create_nordigen_client` and `BankAccountManager` from the `nordigen_account` package. ```python from nordigen_account import create_nordigen_client, BankAccountManager client, token = create_nordigen_client(secret_id, secret_key) manager = BankAccountManager(client, requisition_id) for account in manager.accounts: account.update_account_data() account.update_balance_data() print(f"{account.name}: {account.currency}") ``` -------------------------------- ### BankAccountManager Initialization Example Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/BankAccountManager.md Instantiate BankAccountManager with a Nordigen client and requisition ID. The constructor automatically initializes linked accounts and validates requisition status. ```python manager = BankAccountManager(client, requisition_id="req-123") # After initialization: # - manager.accounts contains BankAccount instances # - manager.institution_id and manager.reference are set # - Requisition status has been validated ``` -------------------------------- ### Cross-References Example Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/README.md Demonstrates how documentation files cross-reference related files and concepts using Markdown links and special characters. ```markdown [BankAccount](BankAccount.md) — Related class documentation [errors.md](errors.md) — Error handling reference [[name]] — Links to other memory/docs ``` -------------------------------- ### Install Nordigen Package Source: https://github.com/rahulpdev/nordigen_account/blob/main/README.md Install the Nordigen Python package using pip. Ensure Python 3.7+ is installed. ```bash pip install nordigen ``` -------------------------------- ### JSON API Response Example Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/README.md Shows a sample JSON structure representing an API response format. ```json { "api": "response format" } ``` -------------------------------- ### Python Code Block Example Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/README.md Illustrates a basic Python code structure including import statements and function calls. ```python # Python example code from package import function function(param="value") ``` -------------------------------- ### Handle Nordigen Token Expiration Automatically Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/create_nordigen_client.md This example demonstrates how to use a try-except block to catch `NordigenAPIError` during client creation. It specifically handles cases where the provided refresh token might be expired, allowing for automatic token regeneration and persistence of the new token. ```python from nordigen_account import create_nordigen_client, NordigenAPIError try: client, new_token = create_nordigen_client( secret_id="your-secret-id", secret_key="your-secret-key", refresh_token=stored_token ) if new_token: # Token was expired; persist the new one update_stored_token(new_token) except NordigenAPIError as e: print(f"Failed to authenticate: {e.message}") if e.status_code == 401: print("Invalid credentials; check secret_id and secret_key") ``` -------------------------------- ### Initialize Nordigen Client with Environment Variables Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/configuration.md This snippet shows how to create a Nordigen client by fetching credentials from environment variables. It also demonstrates how to handle a newly generated token. ```python import os from nordigen_account import create_nordigen_client secret_id = os.getenv("NORDIGEN_SECRET_ID") secret_key = os.getenv("NORDIGEN_SECRET_KEY") refresh_token = os.getenv("NORDIGEN_REFRESH_TOKEN") client, new_token = create_nordigen_client(secret_id, secret_key, refresh_token) # If new token generated, update environment or persistent storage if new_token: # Update storage: environment, database, secrets manager, etc. pass ``` -------------------------------- ### Initialize BankAccount with Constructor Options Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/INDEX.md Create a BankAccount instance, optionally fetching data upon initialization. Requires an authenticated Nordigen client and the account ID. ```python # Account class BankAccount( client: NordigenClient, # Authenticated client account_id: str, # Account identifier fetch_data: bool = False # Fetch data on init ) ``` -------------------------------- ### Standard Nordigen Client Initialization Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/MODULE_GUIDE.md Demonstrates the standard pattern for initializing the Nordigen client and bank account manager, fetching data on demand. ```python # 1. Create client client, refresh_token = create_nordigen_client(secret_id, secret_key, old_token) # 2. Create manager (lazy loading) manager = BankAccountManager(client, requisition_id, fetch_data=False) # 3. Fetch data on demand for account in manager.accounts: account.update_account_data() account.update_balance_data() ``` -------------------------------- ### Fetch Data on Initialization Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/BankAccount.md Shows how to create a BankAccount instance and immediately fetch its data by setting `fetch_data=True` during initialization. ```python # Fetch immediately account = BankAccount(client, account_id="account-789", fetch_data=True) # account.name, account.status, account.currency, account.balances now populated ``` -------------------------------- ### Type Aliases within Class Scope Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/MODULE_GUIDE.md Example of defining type aliases within a class scope for improved readability and documentation of expected API response structures. These aliases are scoped to the class. ```python class BankAccount: DetailsApiResponseType = Dict[str, Dict[str, str]] BalancesApiResponseType = Dict[str, List[Dict[str, Union[Dict[str, str], str, bool]]]] ``` -------------------------------- ### Instantiate Nordigen Client with Credentials Source: https://github.com/rahulpdev/nordigen_account/blob/main/README.md Use `create_nordigen_client` to initialize the client. It accepts secret ID, secret key, and an optional refresh token. If no refresh token is provided, it attempts to generate one. ```python from nordigen_account import create_nordigen_client # Replace with your actual credentials secret_id = "your-secret-id" secret_key = "your-secret-key" refresh_token = "your-refresh-token" # Optional client, new_refresh_token = create_nordigen_client(secret_id, secret_key, refresh_token) ``` -------------------------------- ### Conditional Handling of NordigenAPIError by Status Code Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/NordigenAPIError.md Handle specific NordigenAPIError status codes to implement conditional logic. For example, re-prompting authorization for 410 errors or creating new requisitions for 428 errors. ```python from nordigen_account import BankAccountManager, NordigenAPIError def initialize_manager(client, requisition_id): try: return BankAccountManager(client, requisition_id) except NordigenAPIError as e: if e.status_code == 428: # Expired requisition; create a new one return create_new_requisition(client) elif e.status_code == 410: # No accounts linked; prompt user to authorize redirect_to_authorization(client) elif e.status_code == 404: # Invalid requisition ID raise ValueError(f"Requisition {requisition_id} not found") from e else: # Generic API error raise ``` -------------------------------- ### Set Up Nordigen Client with Token Persistence Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/INDEX.md Creates a Nordigen client, loading a refresh token from a local file if available. If a new token is obtained, it's saved back to the file with restricted permissions. ```python import os import json from pathlib import Path from nordigen_account import create_nordigen_client TOKEN_FILE = Path.home() / ".nordigen_token.json" def get_client(): # Load saved token token = None if TOKEN_FILE.exists(): with open(TOKEN_FILE) as f: token = json.load(f).get("refresh_token") # Create/refresh client client, new_token = create_nordigen_client( secret_id=os.getenv("NORDIGEN_SECRET_ID"), secret_key=os.getenv("NORDIGEN_SECRET_KEY"), refresh_token=token ) # Save if refreshed if new_token: TOKEN_FILE.parent.mkdir(exist_ok=True) with open(TOKEN_FILE, "w") as f: json.dump({"refresh_token": new_token}, f) TOKEN_FILE.chmod(0o600) return client client = get_client() ``` -------------------------------- ### Initialize BankAccount Instance Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/BankAccount.md Instantiate a BankAccount object. Use `fetch_data=True` to immediately retrieve account details and balances upon creation. ```python from nordigen_account import BankAccount # Create account instance without fetching data account = BankAccount(client, account_id="account-123") # Or fetch data immediately account = BankAccount(client, account_id="account-123", fetch_data=True) ``` -------------------------------- ### Handle Requisition Expiration and Authorization Status Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/INDEX.md Attempts to get a BankAccountManager, raising specific ValueErrors for requisition expiration (428) or if no accounts are linked (410), prompting the user to re-authorize or complete the linking process. ```python from nordigen_account import BankAccountManager, NordigenAPIError def get_manager(client, req_id): try: return BankAccountManager(client, req_id, fetch_data=True) except NordigenAPIError as e: if e.status_code == 428: raise ValueError("Requisition expired; create a new one") from e elif e.status_code == 410: raise ValueError("No accounts linked; complete authorization") from e else: raise try: manager = get_manager(client, requisition_id) except ValueError as e: print(f"Configuration error: {e}") # Redirect user to authorization flow ``` -------------------------------- ### Initialize BankAccountManager with Constructor Options Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/INDEX.md Instantiate a BankAccountManager to handle multiple accounts. Data can be fetched upon initialization. Requires an authenticated client and requisition ID. ```python # Manager class BankAccountManager( client: NordigenClient, # Authenticated client requisition_id: str, # Requisition identifier fetch_data: bool = False # Fetch data on init ) ``` -------------------------------- ### Full Workflow: Fetch and Display Account Data Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/BankAccount.md Demonstrates initializing the Nordigen client, creating a BankAccount instance, and fetching/displaying account and balance data. Handles potential API errors. ```python from nordigen_account import create_nordigen_client, BankAccount, NordigenAPIError # Initialize client client, _ = create_nordigen_client(secret_id, secret_key, refresh_token) # Create account instance account = BankAccount(client, account_id="account-456") # Fetch latest data try: account.update_account_data() account.update_balance_data() # Display account info print(f"Name: {account.name}") print(f"Status: {account.status}") print(f"Currency: {account.currency}") print("\nBalances:") for balance in account.balances: print(f" {balance['balanceType']}: {balance['amount']} {balance['currency']}") except NordigenAPIError as e: print(f"Error: {e.message}") ``` -------------------------------- ### Nordigen Client Initialization and Token Generation Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/MODULE_GUIDE.md Illustrates the process of creating a Nordigen client, including checking and generating access/refresh tokens. Handles token expiration and regeneration. ```python create_nordigen_client(secret_id, secret_key, refresh_token) │ ├─→ NordigenClient(secret_id, secret_key) │ ├─→ [Check refresh_token] │ │ │ ├─ If None: generate_token() │ │ → extract "access" and "refresh" │ │ → return (client with access_token, refresh_token) │ │ │ ├─ If provided: exchange_token(refresh_token) │ │ ├─ Success: extract "access" │ │ │ → return (client with access_token, None) │ │ │ │ │ └─ 401 Error: token expired │ │ → falls back to generate_token() │ │ → return (client, new_refresh_token) │ │ │ └─ Other error: raise NordigenAPIError │ └─→ Return (configured_client, refresh_token_or_none) ``` -------------------------------- ### Eager Loading with Bank Account Manager Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/MODULE_GUIDE.md Shows how to initialize the BankAccountManager to fetch all data immediately upon creation. ```python # All data fetched immediately manager = BankAccountManager(client, requisition_id, fetch_data=True) for account in manager.accounts: # Data already available print(account.name) ``` -------------------------------- ### Create Nordigen Client with Constructor Options Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/INDEX.md Instantiate the Nordigen client using explicit constructor parameters. The refresh token is optional and will be auto-generated if not provided. ```python # Factory function create_nordigen_client( secret_id: str, # API secret ID secret_key: str, # API secret key refresh_token: Optional[str] # Refresh token (auto-generated if None) ) ``` -------------------------------- ### Create Nordigen Client and Fetch Account Data Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/README.md Initialize the Nordigen client with your API credentials and then use the BankAccountManager to fetch and update account and balance data. Ensure you have your secret ID, secret key, and requisition ID. ```python from nordigen_account import create_nordigen_client, BankAccountManager # Create client client, token = create_nordigen_client("secret-id", "secret-key") # Load accounts manager = BankAccountManager(client, "requisition-id") # Fetch data for account in manager.accounts: account.update_account_data() account.update_balance_data() print(f"{account.name}: {account.currency}") ``` -------------------------------- ### Initialize Nordigen Client Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/API_REFERENCE.md Use this function to create a Nordigen client instance. Ensure you save the refresh token for subsequent uses. ```python from nordigen_account import create_nordigen_client client, refresh_token = create_nordigen_client( secret_id="your-secret-id", secret_key="your-secret-key" ) # Save refresh_token for future use ``` -------------------------------- ### Resource Management Without Context Managers Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/MODULE_GUIDE.md Demonstrates direct usage of the Nordigen client and manager without relying on Python's context managers. No explicit cleanup is required as objects are garbage collected. ```python # No need for 'with' statements client, token = create_nordigen_client(secret_id, secret_key) manager = BankAccountManager(client, requisition_id) # Direct usage; no cleanup needed for account in manager.accounts: account.update_balance_data() # Can be garbage collected normally ``` -------------------------------- ### Create Nordigen Client Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/configuration.md Use `create_nordigen_client` to initialize a Nordigen client. It handles token generation and refresh. Provide your API credentials and optionally a refresh token for reuse. ```python create_nordigen_client( secret_id: str, secret_key: str, refresh_token: Optional[str] = None ) -> Tuple[NordigenClient, str] ``` -------------------------------- ### Initialize BankAccount Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/configuration.md Initialize a `BankAccount` instance with a Nordigen client and account ID. Set `fetch_data=True` to immediately retrieve account details and balances. ```python BankAccount( client: NordigenClient, account_id: str, fetch_data: bool = False ) -> BankAccount ``` -------------------------------- ### Lazy Loading Initialization Comparison Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/INDEX.md Illustrates the performance difference between initializing a BankAccountManager with fetch_data=False (lazy loading) versus fetch_data=True. Lazy loading offers faster initialization at the cost of slower first access. ```python # Fast initialization, slow first access manager = BankAccountManager(client, req_id, fetch_data=False) # ~10ms # Slow initialization, fast access manager = BankAccountManager(client, req_id, fetch_data=True) # ~5s ``` -------------------------------- ### Basic Nordigen Account Usage Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/INDEX.md Demonstrates how to create an authenticated client, load bank accounts using a requisition ID, and fetch/display account and balance data. Ensure you have your secret ID, secret key, and requisition ID. ```python from nordigen_account import create_nordigen_client, BankAccountManager # 1. Create authenticated client client, token = create_nordigen_client( secret_id="your-secret-id", secret_key="your-secret-key" ) # 2. Load accounts for requisition manager = BankAccountManager(client, requisition_id="your-requisition-id") # 3. Fetch and display account data for account in manager.accounts: account.update_account_data() account.update_balance_data() print(f"{account.name} ({account.currency})") for balance in account.balances: print(f" {balance['balanceType']}: {balance['amount']}") ``` -------------------------------- ### Initialize BankAccountManager and Load Accounts Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/BankAccountManager.md Instantiate the BankAccountManager to load all linked bank accounts for a given requisition. Use `fetch_data=True` to immediately retrieve account and balance data upon initialization. ```python from nordigen_account import create_nordigen_client, BankAccountManager client, _ = create_nordigen_client(secret_id, secret_key, refresh_token) # Create manager and load accounts manager = BankAccountManager(client, requisition_id="req-123") ``` ```python # Or fetch account data immediately manager = BankAccountManager(client, requisition_id="req-123", fetch_data=True) ``` -------------------------------- ### Initialize BankAccountManager Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/configuration.md Initialize a `BankAccountManager` with a Nordigen client and requisition ID. Set `fetch_data=True` to fetch data for all linked accounts upon initialization. ```python BankAccountManager( client: NordigenClient, requisition_id: str, fetch_data: bool = False ) -> BankAccountManager ``` -------------------------------- ### Create Nordigen Client and BankAccountManager Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/BankAccountManager.md Initializes the Nordigen client and creates a BankAccountManager instance for a specific requisition. Handles potential API errors like expired requisitions or missing account data. ```python from nordigen_account import create_nordigen_client, BankAccountManager, NordigenAPIError # Setup client, _ = create_nordigen_client(secret_id, secret_key, refresh_token) # Create manager try: manager = BankAccountManager(client, requisition_id="req-456") # Access loaded accounts print(f"Institution: {manager.institution_id}") print(f"Number of accounts: {len(manager.accounts)}") for account in manager.accounts: print(f" Account ID: {account._account_id}") except NordigenAPIError as e: if e.status_code == 428: print("Requisition has expired; create a new one") elif e.status_code == 410: print("No accounts found; complete bank authorization") else: print(f"Error: {e.message}") ``` -------------------------------- ### Account Loading Data Flow Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/INDEX.md Details the steps involved in initializing and loading bank accounts using the BankAccountManager. ```text BankAccountManager() └─ _initialize_accounts() ├─ Fetch requisition by ID ├─ Validate status (not expired) ├─ Validate accounts list (not empty) └─ Create BankAccount for each account_id ``` -------------------------------- ### Initialize Bank Account Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/INDEX.md Represents a single bank account. Use this to fetch account details and balances. Set fetch_data to True to immediately retrieve name, status, and currency. ```python account = BankAccount(client, account_id, fetch_data=False) account.update_account_data() # Fetch name, status, currency account.update_balance_data() # Fetch balances ``` -------------------------------- ### Fetch Data on Initialization Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/BankAccountManager.md Initializes the BankAccountManager and automatically fetches account data for all associated accounts upon creation by setting `fetch_data=True`. ```python # Automatically fetch account data for all accounts manager = BankAccountManager( client, requisition_id="req-123", fetch_data=True ) # All accounts have data already fetched for account in manager.accounts: print(account.name, account.balances) ``` -------------------------------- ### Client Creation Data Flow Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/INDEX.md Illustrates the process of creating a Nordigen client, including token refresh and fallback mechanisms. ```text create_nordigen_client() ├─ Check refresh_token ├─ If None: generate_token() ├─ If provided: exchange_token() │ └─ If 401: falls back to generate_token() └─ Return (client, new_token_or_none) ``` -------------------------------- ### Create Nordigen Client Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/INDEX.md Factory function for client initialization. Returns a configured client and a new refresh token if one is generated. ```python create_nordigen_client(secret_id, secret_key, refresh_token=None) → (NordigenClient, str) ``` -------------------------------- ### Create Nordigen Client and Generate New Token Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/create_nordigen_client.md Use this snippet when no existing refresh token is available. It initializes the Nordigen client and generates a new access and refresh token pair. ```python from nordigen_account import create_nordigen_client secret_id = "your-secret-id" secret_key = "your-secret-key" client, new_refresh_token = create_nordigen_client(secret_id, secret_key) # Store the generated token for future use if new_refresh_token: print(f"Save this token: {new_refresh_token}") ``` -------------------------------- ### Create Nordigen Client and Reuse Existing Refresh Token Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/create_nordigen_client.md Use this snippet to initialize the Nordigen client with a valid, existing refresh token. The client will attempt to use this token to obtain an access token. ```python from nordigen_account import create_nordigen_client client, refreshed_token = create_nordigen_client( secret_id="your-secret-id", secret_key="your-secret-key", refresh_token="existing-refresh-token" ) # If token was refreshed due to expiration, store the new one if refreshed_token: print(f"Token was expired; save this new one: {refreshed_token}") ``` -------------------------------- ### Account Balance Update Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/MODULE_GUIDE.md Demonstrates fetching and updating the balance information for a bank account, including converting amounts and currency. ```python BankAccount.update_balance_data() │ ├─→ client.account_api(id=account_id).get_balances() │ ├─→ Clear self.balances list │ ├─→ For each balance in response.balances[]: │ ├─ Extract: balanceType │ ├─ Extract: balanceAmount.amount (convert str → float) │ ├─ Extract: balanceAmount.currency │ └─ Append {balanceType, amount, currency} to self.balances │ └─→ Return (errors → NordigenAPIError) ``` -------------------------------- ### Set Environment Variables for Nordigen API Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/INDEX.md Configure Nordigen API credentials and tokens using environment variables. This is the recommended method for setting up the client. ```bash export NORDIGEN_SECRET_ID="your-id" export NORDIGEN_SECRET_KEY="your-key" export NORDIGEN_REFRESH_TOKEN="your-token" export NORDIGEN_REQUISITION_ID="your-requisition" ``` -------------------------------- ### Module Composition Diagram Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/MODULE_GUIDE.md Illustrates the package structure, public API entry points, type aliases, and internal methods of the nordigen_account package. ```text nordigen_account (package) │ ├── Entry Points (Public API) │ ├── create_nordigen_client() → NordigenClient, str │ ├── NordigenAPIError → Exception │ ├── BankAccount → Class │ └── BankAccountManager → Class │ ├── Type Aliases (Internal) │ ├── BankAccount.DetailsApiResponseType │ ├── BankAccount.BalancesApiResponseType │ └── BankAccountManager.RequisitionApiResponseType │ └── Internal Methods ├── BankAccount.update_account_data() ├── BankAccount.update_balance_data() └── BankAccountManager._initialize_accounts() ``` -------------------------------- ### Instantiate NordigenAPIError Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/NordigenAPIError.md Shows how to create instances of NordigenAPIError with different levels of detail, including just a message, or a message with status code and response body. ```python from nordigen_account import NordigenAPIError # Create with message only error = NordigenAPIError("Token generation failed") # Create with status and response error = NordigenAPIError( message="Invalid requisition ID", status_code=404, response_body={"detail": "Requisition not found"} ) ``` -------------------------------- ### Thread-Safe Client Initialization Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/MODULE_GUIDE.md Provides a safe way to handle Nordigen clients in multi-threaded environments by ensuring each thread has its own client instance. ```python # Safe: Each thread gets its own client def worker(): client, _ = create_nordigen_client(secret_id, secret_key, token) manager = BankAccountManager(client, requisition_id) # Use manager in this thread only # Unsafe: Shared client across threads client = create_nordigen_client(secret_id, secret_key, token)[0] for thread in threads: thread.use(client) # DON'T DO THIS ``` -------------------------------- ### Manage Bank Accounts with BankAccountManager Source: https://github.com/rahulpdev/nordigen_account/blob/main/README.md Instantiate `BankAccountManager` with the client and requisition ID to manage multiple bank accounts. Set `fetch_data=True` to automatically collect account data upon initialization. ```python from nordigen_account import BankAccountManager requisition_id = "your-requisition-id" # Instantiate account manager manager = BankAccountManager(client, requisition_id, fetch_data=True) # Access account details for account in manager.accounts: print("Account ID:", account._account_id) print("Balances:", account.balances) ``` -------------------------------- ### Load Bank Accounts Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/API_REFERENCE.md Initialize a BankAccountManager with the client and a requisition ID to access linked bank accounts. ```python from nordigen_account import BankAccountManager manager = BankAccountManager(client, requisition_id="your-requisition-id") # Access accounts for account in manager.accounts: print(f"Account ID: {account._account_id}") ``` -------------------------------- ### Account Loading Flow Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/MODULE_GUIDE.md Details the process of initializing account managers and loading bank account details. Includes validation steps for requisition status and account lists. ```python BankAccountManager(client, requisition_id) │ └─→ _initialize_accounts() │ ├─→ requisition.get_requisition_by_id(requisition_id) │ └─ Extract: institution_id, reference, status, accounts[] │ ├─→ [Validate status] │ ├─ If "EX": raise NordigenAPIError (428) │ └─ Otherwise: continue │ ├─→ [Validate accounts list] │ ├─ If empty: raise NordigenAPIError (410) │ └─ Otherwise: continue │ └─→ For each account_id in accounts[]: └─→ BankAccount(client, account_id, fetch_data) └─ Store in self.accounts list ``` -------------------------------- ### Create Nordigen Client Factory Function Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/README.md Use this factory function to create an instance of the Nordigen client. It requires your secret ID and secret key, with an optional refresh token. ```python # Factory function create_nordigen_client(secret_id, secret_key, refresh_token=None) ``` -------------------------------- ### create_nordigen_client Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/create_nordigen_client.md Factory function that initializes a `NordigenClient` with authentication credentials. Handles token generation and refresh token lifecycle, returning both the configured client and any newly generated refresh token. ```APIDOC ## create_nordigen_client ### Description Factory function that initializes a `NordigenClient` with authentication credentials. Handles token generation and refresh token lifecycle, returning both the configured client and any newly generated refresh token. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Method Signature ```python def create_nordigen_client( secret_id: str, secret_key: str, refresh_token: Optional[str] = None ) -> Tuple[NordigenClient, str]: ``` ### Parameters - **secret_id** (str) - Required - Nordigen API secret ID obtained from developer portal - **secret_key** (str) - Required - Nordigen API secret key obtained from developer portal - **refresh_token** (Optional[str]) - Optional - Valid refresh token for obtaining access token. If omitted or expired, a new token is generated ### Return Type `Tuple[NordigenClient, str]` - **First element** (`NordigenClient`): Authenticated client instance with access token set, ready for API calls - **Second element** (str): Newly generated refresh token if token generation or refresh occurred; otherwise `None` ### Behavior #### When `refresh_token` is not provided Generates new tokens from scratch using credentials: 1. Calls `client.generate_token()` 2. Extracts `access` token and sets it on client 3. Returns newly generated `refresh` token #### When `refresh_token` is provided Attempts to use existing token: 1. Calls `client.exchange_token(refresh_token)` with provided token 2. If successful: extracts `access` token, returns client and `None` 3. If 401 (Unauthorized): token is expired, falls back to generating new tokens 4. If other HTTP error: raises `NordigenAPIError` with full response details ### Error Handling Raises `NordigenAPIError` in the following cases: - **Token generation/exchange fails**: HTTP error other than 401 during token operations (e.g., invalid credentials) - **Expired refresh token (401)**: Automatically generates new token; no exception raised - **Malformed API response**: Missing `access` or `refresh` key in response (KeyError) - **Network/unexpected errors**: Any exception during token acquisition ### Usage Example #### Generate new token if none exists ```python from nordigen_account import create_nordigen_client secret_id = "your-secret-id" secret_key = "your-secret-key" client, new_refresh_token = create_nordigen_client(secret_id, secret_key) # Store the generated token for future use if new_refresh_token: print(f"Save this token: {new_refresh_token}") ``` #### Reuse existing refresh token ```python from nordigen_account import create_nordigen_client client, refreshed_token = create_nordigen_client( secret_id="your-secret-id", secret_key="your-secret-key", refresh_token="existing-refresh-token" ) # If token was refreshed due to expiration, store the new one if refreshed_token: print(f"Token was expired; save this new one: {refreshed_token}") ``` #### Handle token expiration automatically ```python from nordigen_account import create_nordigen_client, NordigenAPIError try: client, new_token = create_nordigen_client( secret_id="your-secret-id", secret_key="your-secret-key", refresh_token=stored_token ) if new_token: # Token was expired; persist the new one update_stored_token(new_token) except NordigenAPIError as e: print(f"Failed to authenticate: {e.message}") if e.status_code == 401: print("Invalid credentials; check secret_id and secret_key") ``` ``` -------------------------------- ### Basic NordigenAPIError Handling Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/NordigenAPIError.md Catch NordigenAPIError during client creation to handle initialization failures gracefully. Prints the error message and exits. ```python from nordigen_account import create_nordigen_client, NordigenAPIError try: client, token = create_nordigen_client(secret_id, secret_key, refresh_token) except NordigenAPIError as e: print(f"Failed to create client: {e.message}") exit(1) ``` -------------------------------- ### Class Relationships Diagram Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/MODULE_GUIDE.md Visualizes the relationships between NordigenClient, BankAccount, and BankAccountManager, highlighting how the client is provided to the other classes. ```text ┌──────────────────┐ │ NordigenClient │ (from nordigen package) └────────┬─────────┘ │ (provided to) │ ┌────────────────────┼────────────────────┐ │ │ │ ▼ ▼ ▼ [Function] [BankAccount] [BankAccountManager] create_nordigen - name - accounts: List[BankAccount] _client() - status - institution_id Returns: - currency - reference (client, token) - balances ``` -------------------------------- ### Token Refresh Strategy with Nordigen Client Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/configuration.md Demonstrates a robust token refresh strategy. It attempts to use an existing refresh token, handles potential API errors, and saves a newly generated token to a file. ```python from nordigen_account import create_nordigen_client, NordigenAPIError import json import os # Load stored credentials stored_token = os.getenv("NORDIGEN_REFRESH_TOKEN") try: # Attempt to use existing token client, new_token = create_nordigen_client( secret_id=os.getenv("NORDIGEN_SECRET_ID"), secret_key=os.getenv("NORDIGEN_SECRET_KEY"), refresh_token=stored_token ) # If new token generated (old one expired), persist it if new_token: # Update storage with open(".tokens.json", "w") as f: json.dump({"refresh_token": new_token}, f) print("Token refreshed and saved") else: print("Existing token is still valid") except NordigenAPIError as e: print(f"Authentication failed: {e.message}") ``` -------------------------------- ### Fetch Latest Account Balances Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/API_REFERENCE.md Fetches and prints the latest balances for all accounts associated with a requisition ID. It handles token creation and refresh automatically. Requires NORDIGEN_SECRET_ID, NORDIGEN_SECRET_KEY, and NORDIGEN_REQUISITION_ID environment variables. ```python from nordigen_account import create_nordigen_client, BankAccountManager, NordigenAPIError import os try: # Create client client, new_token = create_nordigen_client( secret_id=os.getenv("NORDIGEN_SECRET_ID"), secret_key=os.getenv("NORDIGEN_SECRET_KEY"), refresh_token=os.getenv("NORDIGEN_REFRESH_TOKEN") ) if new_token: # Save new refresh token os.environ["NORDIGEN_REFRESH_TOKEN"] = new_token # Load accounts manager = BankAccountManager(client, os.getenv("NORDIGEN_REQUISITION_ID")) # Fetch balances for account in manager.accounts: account.update_balance_data() for balance in account.balances: print(f"{balance['balanceType']}: {balance['amount']} {balance['currency']}") except NordigenAPIError as e: print(f"Error: {e.message}") if e.status_code: print(f"HTTP {e.status_code}") ``` -------------------------------- ### Direct Account Access by ID Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/MODULE_GUIDE.md Illustrates how to directly access a specific bank account using its ID, bypassing the manager and fetching data immediately. ```python # Bypass manager if you know account ID account = BankAccount(client, known_account_id, fetch_data=True) # Data fetched print(account.name, account.balances) ``` -------------------------------- ### Lazy vs. Eager Loading of Account Data Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/configuration.md Choose between lazy loading (default, faster initialization) and eager loading (slower initialization, faster data access) for BankAccountManager. Lazy loading fetches data on demand, while eager loading fetches all data upfront. ```python # LAZY LOADING (default) # Faster initialization, slower data access manager = BankAccountManager(client, requisition_id, fetch_data=False) for account in manager.accounts: account.update_account_data() # Fetch on demand account.update_balance_data() # EAGER LOADING # Slower initialization, faster data access manager = BankAccountManager(client, requisition_id, fetch_data=True) for account in manager.accounts: print(account.name) # Already fetched ``` -------------------------------- ### Clone Nordigen Account Repository Source: https://github.com/rahulpdev/nordigen_account/blob/main/README.md Use this command to clone the project repository from GitHub. ```bash git clone https://github.com/rahulpdev/nordigen_account.git cd nordigen_account ``` -------------------------------- ### Account Data Fetching Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/INDEX.md Explains how account details and balance data are fetched and parsed. ```text BankAccount.update_account_data() └─ Fetch from account_api().get_details() └─ Extract: name, status, currency ``` ```text BankAccount.update_balance_data() └─ Fetch from account_api().get_balances() └─ Parse: balanceType, amount (float), currency ``` -------------------------------- ### Fetch and Display Account Details Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/BankAccountManager.md Fetches updated account details and balance information for all accounts associated with a requisition. Displays account names, currencies, statuses, and balance types with amounts. ```python manager = BankAccountManager(client, requisition_id="req-789") # Manually fetch account details for account in manager.accounts: try: account.update_account_data() account.update_balance_data() except NordigenAPIError as e: print(f"Failed to update {account._account_id}: {e.message}") # Display all accounts for account in manager.accounts: print(f"\n{account.name} ({account.currency})") print(f"Status: {account.status}") for balance in account.balances: print(f" {balance['balanceType']}: {balance['amount']}") ``` -------------------------------- ### Sequential vs. Parallel Fetching for Account Data Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/INDEX.md Compares sequential fetching with parallel fetching using ThreadPoolExecutor for updating account data. Use parallel fetching for improved performance when dealing with multiple accounts. ```python # Slower: Sequential fetching for account in manager.accounts: account.update_account_data() # Blocks # Faster: Parallel fetching (with threading) import concurrent.futures with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor: executor.map(lambda a: a.update_account_data(), manager.accounts) ``` -------------------------------- ### Account Details Update Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/MODULE_GUIDE.md Shows how to fetch and update the basic details of a bank account using the Nordigen client. ```python BankAccount.update_account_data() │ ├─→ client.account_api(id=account_id).get_details() │ ├─→ Extract account object │ ├─ name → self.name │ ├─ status → self.status │ └─ currency → self.currency │ └─→ Return (errors → NordigenAPIError) ``` -------------------------------- ### Commonly Used Built-in Type Hints Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/MODULE_GUIDE.md Lists common Python type hints used for containers, optionality, and primitive types, aiding in understanding method signatures and data structures. ```python # Containers Dict[str, T] # Dictionaries List[T] # Lists Tuple[T, U] # Tuples (fixed size) # Optionality Optional[T] # Equivalent to Union[T, None] Union[T, U] # Either type # Primitives str # Strings int # Integers float # Floats bool # Booleans ``` -------------------------------- ### Token Expiration Management Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/MODULE_GUIDE.md Illustrates how to manage Nordigen API tokens, including generating a new token on first run and refreshing/saving it on subsequent runs when it expires. ```python # On first run: generate new token client, new_token = create_nordigen_client(secret_id, secret_key, None) # save new_token # On subsequent runs: reuse token client, refreshed = create_nordigen_client(secret_id, secret_key, saved_token) if refreshed: # Token was expired; save the new one save(refreshed) ``` -------------------------------- ### Secure Credential Storage with Environment Variables Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/configuration.md Use environment variables to store sensitive credentials like secret IDs and keys, especially in CI/CD pipelines. Avoid hardcoding credentials directly in your code. ```python # Use environment variables for CI/CD import os secret_id = os.getenv("NORDIGEN_SECRET_ID") secret_key = os.getenv("NORDIGEN_SECRET_KEY") # Use secrets manager for production from some_secrets_library import get_secret secret_id = get_secret("nordigen/secret_id") secret_key = get_secret("nordigen/secret_key") # Never hardcode or commit credentials # ❌ DON'T DO THIS: # secret_id = "prod-secret-abc123" ``` -------------------------------- ### Handle Unexpected Exceptions During Requisition Fetch Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/errors.md Catch NordigenAPIError for unexpected issues like network errors or timeouts during requisition initialization. Check network connectivity. ```python try: manager = BankAccountManager(client, requisition_id="req-123") except NordigenAPIError as e: if "Unexpected error" in e.message: print("Check network connectivity") ``` -------------------------------- ### BankAccount Class Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/README.md Represents a bank account. Instantiate with a client, account ID, and an option to fetch data upon initialization. ```python # Account classes BankAccount(client, account_id, fetch_data=False) ``` -------------------------------- ### Handle Requisition Initialization Errors Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/NordigenAPIError.md Catch NordigenAPIError during BankAccountManager initialization to address issues like expired requisitions, missing linked accounts, or invalid requisition IDs. The status code helps identify the specific problem. ```python from nordigen_account import BankAccountManager, NordigenAPIError try: manager = BankAccountManager(client, requisition_id="req-123") except NordigenAPIError as e: if e.status_code == 428: print("Requisition expired; create a new one") elif e.status_code == 410: print("No accounts; complete bank authorization") elif e.status_code == 404: print("Requisition ID is invalid") else: print(f"Error: {e.message}") ``` -------------------------------- ### Fetch Account Data and Balances Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/API_REFERENCE.md Update account details and balance information for each account managed by the BankAccountManager. This allows retrieval of specific balance types and amounts. ```python # Fetch account details and balances for account in manager.accounts: account.update_account_data() account.update_balance_data() print(f"{account.name}: {account.currency}") for balance in account.balances: print(f" {balance['balanceType']}: {balance['amount']}") ``` -------------------------------- ### Token Persistence and Refresh Logic Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/configuration.md Implement logic to load and save Nordigen API refresh tokens to a file. This ensures that tokens persist across application restarts and can be refreshed when needed. Permissions are restricted to owner. ```python import json from pathlib import Path from nordigen_account import create_nordigen_client TOKEN_FILE = Path("~/.nordigen_tokens.json").expanduser() def load_refresh_token(): if TOKEN_FILE.exists(): with open(TOKEN_FILE) as f: return json.load(f).get("refresh_token") return None def save_refresh_token(token): TOKEN_FILE.parent.mkdir(exist_ok=True) with open(TOKEN_FILE, "w") as f: json.dump({"refresh_token": token}, f) TOKEN_FILE.chmod(0o600) # Restrict permissions # Usage stored_token = load_refresh_token() client, new_token = create_nordigen_client(secret_id, secret_key, stored_token) if new_token: save_refresh_token(new_token) ``` -------------------------------- ### Async Operation with ThreadPoolExecutor Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/INDEX.md Shows how to perform asynchronous operations, like updating balance data, within an async context using a ThreadPoolExecutor. This is a workaround for the lack of native async support. ```python import asyncio from concurrent.futures import ThreadPoolExecutor async def async_fetch(): with ThreadPoolExecutor() as executor: loop = asyncio.get_event_loop() await loop.run_in_executor(executor, manager.accounts[0].update_balance_data) ``` -------------------------------- ### Check Account Status Source: https://github.com/rahulpdev/nordigen_account/blob/main/_autodocs/API_REFERENCE.md Iterates through accounts and prints their readiness status. This snippet assumes a client and requisition_id are already available. It catches potential API errors during status retrieval. ```python from nordigen_account import BankAccountManager, NordigenAPIError manager = BankAccountManager(client, requisition_id) try: for account in manager.accounts: account.update_account_data() if account.status == "READY": print(f"✓ {account.name} ({account.currency}) is ready") else: print(f"⚠ {account.name} status: {account.status}") except NordigenAPIError as e: print(f"Failed to check status: {e.message}") ``` -------------------------------- ### Handle New Refresh Token Generation Source: https://github.com/rahulpdev/nordigen_account/blob/main/README.md Check if a new refresh token was generated during client instantiation. If so, print it and ensure it's stored securely for future use. ```python client, new_refresh_token = create_nordigen_client(secret_id, secret_key, refresh_token) if new_refresh_token: print("New refresh token generated:", new_refresh_token) # Store the new token securely for future API requests ```