How API Endpoints Are Organized in Securo: A FastAPI Router Architecture Guide

Securo organizes its REST API endpoints using FastAPI's APIRouter pattern, with domain-specific modules in backend/app/api/ each defining their own URL prefix and tags, then centrally registered in backend/app/main.py.

Securo's backend follows a clean, domain-driven design that makes its API structure predictable and maintainable. Built on FastAPI, the codebase splits every logical group of HTTP endpoints into dedicated router modules. This article breaks down exactly how the securo-finance/securo repository structures its API layer, with specific file paths and wiring patterns you can apply to your own FastAPI projects.

Router Module Structure in backend/app/api/

Each business domain gets its own Python file under backend/app/api/. These files create APIRouter instances with distinct prefixes and tags, then export the router for central registration.

Domain Router Prefix Source File
Workspaces /api/workspaces [workspaces.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/workspaces.py)
Users / Lookup /api/users [user_lookup.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/user_lookup.py)
Accounts /api/accounts [accounts.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/accounts.py)
Transactions /api/transactions [transactions.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/transactions.py)
Import Transactions /api/transactions (tags = "import") [import_transactions.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/import_transactions.py)
Import Logs /api/import-logs [import_logs.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/import_logs.py)
Recurring Transactions /api/recurring-transactions [recurring_transactions.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/recurring_transactions.py)
Assets /api/assets [assets.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/assets.py)
Asset Groups /api/asset-groups [asset_groups.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/asset_groups.py)
Budgets /api/budgets [budgets.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/budgets.py)
Goals /api/goals [goals.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/goals.py)
Categories /api/categories [categories.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/categories.py)
Category Groups /api/category-groups [category_groups.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/category_groups.py)
Payees /api/payees [payees.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/payees.py)
Groups /api/groups [groups.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/groups.py)
Rules /api/rules [rules.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/rules.py)
Settings /api/settings [settings.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/settings.py)
Dashboard /api/dashboard [dashboard.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/dashboard.py)
Reports /api/reports [reports.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/reports.py)
Search /api/search [search.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/search.py)
Export /api/export [export.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/export.py)
Attachments /api/attachments [attachments.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/attachments.py)
Collections /api/collections [collections.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/collections.py)
Connections /api/connections [connections.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/connections.py)
Currencies /api/currencies [currencies.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/currencies.py)
FX Rates /api/fx-rates [fx_rates.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/fx_rates.py)
Fiscal /api/fiscal [fiscal.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/fiscal.py)
Admin /api/admin [admin.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/admin.py)
Two-Factor Auth /api/2fa (router without prefix) [two_factor.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/two_factor.py)
Passkeys /api/passkeys (router without prefix) [passkeys.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/passkeys.py)
OIDC Auth /api/auth/oidc [oidc_auth.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/oidc_auth.py)
Info (general) /api [info.py](https://github.com/securo-finance/securo/blob/main/backend/app/api/info.py)

Special Case: Routers Without Prefixes

Some authentication modules define routes with explicit path prefixes baked into their endpoint decorators rather than the APIRouter prefix parameter. This pattern appears in:

Central Router Registration in main.py

The FastAPI application instance lives in backend/app/main.py. This file imports all router modules and mounts them with app.include_router().


# Simplified structure as implemented in securo-finance/securo

from fastapi import FastAPI
from app.api import (
    workspaces,
    user_lookup,
    transactions,
    assets,
    budgets,
    categories,
    # ... all other router modules

)

app = FastAPI(title="Securo API")

app.include_router(workspaces.router)
app.include_router(user_lookup.router)
app.include_router(transactions.router)
app.include_router(assets.router)
app.include_router(budgets.router)

# ... remaining routers

This central registration pattern ensures:

  • No circular imports — routers depend on main.py, not each other
  • Consistent middleware stack — all routes inherit the same CORS, authentication, and logging layers
  • Single source of truth — one file shows the complete API surface

Agent-Specific API Layer

Securo extends its API organization for AI agent functionality through a separate subpackage. Agent-related endpoints reside in backend/app/agents/api/ and follow the same router pattern.

Domain Router Prefix Source File
Agents (various sub-domains) /api/agents/* [agents.py](https://github.com/securo-finance/securo/blob/main/backend/app/agents/api/agents.py)
Knowledge /api/agents/knowledge [knowledge.py](https://github.com/securo-finance/securo/blob/main/backend/app/agents/api/knowledge.py)
Conversations /api/agents/conversations [conversations.py](https://github.com/securo-finance/securo/blob/main/backend/app/agents/api/conversations.py)

This separation keeps agent logic isolated from core financial operations while maintaining architectural consistency.

Design Principles Behind Securo's API Organization

URL Prefixes Mirror Resource Hierarchy

Every prefix nests under /api/ and uses kebab-case plural nouns. This creates intuitive URLs:


/api/workspaces/{id}/accounts
/api/transactions?workspace_id={id}
/api/assets/{id}/prices

Tags Enable OpenAPI Documentation Grouping

Each router module assigns relevant tags to its endpoints. These appear in the auto-generated Swagger UI at /docs, grouping related operations visually.


# Typical router initialization pattern

from fastapi import APIRouter

router = APIRouter(
    prefix="/api/assets",
    tags=["assets"]
)

Module Size Stays Bounded

No single file accumulates unrelated endpoints. Even closely related domains like transactions and import_transactions split into separate modules based on operation type (CRUD vs. data ingestion).

Practical API Examples

Creating a Workspace

import httpx

async def create_workspace(name: str):
    async with httpx.AsyncClient(base_url="http://localhost:8000") as client:
        response = await client.post(
            "/api/workspaces",
            json={"name": name}
        )
        return response.json()

# → {"id": "ws_abc123", "name": "Personal Finance", "created_at": "2024-01-15T..."}

Listing Assets with Filters

async def list_stocks(workspace_id: str):
    async with httpx.AsyncClient(base_url="http://localhost:8000") as client:
        response = await client.get(
            "/api/assets",
            params={"workspace_id": workspace_id, "type": "stock"}
        )
        return response.json()

# → [{"id": "ast_001", "type": "stock", "symbol": "AAPL", "quantity": 50.0}, ...]

Batch Import Transactions

async def import_csv(workspace_id: str, file_content: bytes):
    async with httpx.AsyncClient(base_url="http://localhost:8000") as client:
        response = await client.post(
            "/api/transactions/import",
            params={"workspace_id": workspace_id},
            files={"file": ("transactions.csv", file_content, "text/csv")}
        )
        return response.json()

# → {"import_id": "imp_789", "rows_processed": 142, "errors": []}

Key Files for Understanding Securo API Organization

File Path Purpose
backend/app/main.py FastAPI app factory; central router registration
backend/app/api/__init__.py Package exports (if present)
backend/app/api/{domain}.py Individual router modules (30+ files)
backend/app/agents/api/ Agent-specific router subpackage
backend/app/core/config.py Settings including API versioning
backend/app/dependencies/ Shared FastAPI dependencies for auth, DB sessions

Summary

  • Domain-driven modules: Each business concept lives in its own file under backend/app/api/
  • Explicit prefixes: Every APIRouter declares its /api/{resource} prefix at initialization
  • Central registration: backend/app/main.py imports and mounts all routers with include_router()
  • Tags for documentation: Logical grouping in OpenAPI/Swagger through consistent tag usage
  • Agent separation: Extended API surface in backend/app/agents/api/ follows identical patterns

Frequently Asked Questions

What pattern does Securo use for FastAPI routing?

Securo uses FastAPI's APIRouter pattern with domain-specific modules. Each file in backend/app/api/ creates a router with a dedicated prefix and tags, then exports it for central registration in main.py. This is the recommended FastAPI pattern for applications with more than a handful of endpoints.

Authentication routes split across multiple specialized modules. OIDC flows live in oidc_auth.py with prefix /api/auth/oidc. Two-factor authentication and passkeys each have dedicated modules (two_factor.py, passkeys.py) that define explicit paths rather than router prefixes. This allows flexible grouping of related but distinct security mechanisms.

Where are agent-specific endpoints located?

Agent API endpoints reside in backend/app/agents/api/ rather than the main backend/app/api/ directory. This subpackage contains agents.py, knowledge.py, conversations.py, and related files, all using the same APIRouter pattern with prefixes under /api/agents/. The separation prevents agent logic from polluting core financial domain code.

Can I add new endpoints without modifying main.py?

In Securo's architecture, yes, but with a required registration step. You create a new module in backend/app/api/ with a router, then explicitly import and include it in backend/app/main.py. There is no auto-discovery mechanism — explicit registration ensures intentional API surface changes and prevents accidental exposure of development or test endpoints.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →