What Is the Purpose of the Rules Engine API in Securo?

The rules engine API in Securo enables users to define, manage, and automatically apply categorization rules to financial transactions through a comprehensive set of CRUD, preview, import/export, and bulk operation endpoints.

The rules engine API serves as the programmatic interface for Securo's transaction categorization system. Located in the backend FastAPI application, this API allows users to create declarative rules that automatically tag and organize financial transactions based on configurable conditions. This article examines the implementation in backend/app/api/rules.py and its supporting service layer to explain exactly how the rules engine functions.

Core Purpose: Automated Transaction Categorization

The rules engine solves a fundamental problem in personal finance management: manually categorizing hundreds or thousands of transactions is tedious and error-prone. The API provides a programmable, user-editable system where rules evaluate transaction fields (description, amount, merchant, etc.) and apply actions like setting a category or adding tags.

According to the Securo source code, the rules engine supports:

  • Rule lifecycle management — Create, read, update, and delete categorization rules
  • Immediate application — Apply rules to existing transactions upon creation or modification
  • Safe experimentation — Preview rule effects without persisting changes
  • Data portability — Export and import rule sets as JSON
  • Pre-built rule packs — Install country-specific or domain-specific rule collections
  • Bulk reprocessing — Re-run all active rules against the entire transaction history

CRUD Operations for Rules

The foundation of the rules engine API is standard resource management for rule objects. These endpoints interact with the rule service to persist rule definitions and enforce workspace-level isolation.

List and Create Rules

The GET /api/rules endpoint retrieves all rules for the current workspace. The POST /api/rules endpoint creates new rules with optional immediate application to existing transactions.


# backend/app/api/rules.py

@router.get("/api/rules")
async def list_rules(
    workspace_ctx: WorkspaceContext = Depends(get_workspace_context),
    rule_service: RuleService = Depends(get_rule_service)
):
    """Retrieve all rules for the current workspace."""
    return await rule_service.list_rules(workspace_ctx.workspace_id)

When creating a rule, the API accepts a boolean apply_to_existing flag. If true, the service immediately applies the new rule to all matching transactions in the workspace:


# backend/app/api/rules.py (simplified)

@router.post("/api/rules")
async def create_rule(
    rule_data: RuleCreate,
    workspace_ctx: WorkspaceContext = Depends(get_workspace_context),
    rule_service: RuleService = Depends(get_rule_service)
):
    created_rule = await rule_service.create_rule(
        workspace_id=workspace_ctx.workspace_id,
        user_id=workspace_ctx.user_id,
        data=rule_data
    )
    
    # Conditionally apply to existing transactions

    if rule_data.apply_to_existing:
        applied_count = await rule_service.apply_single_rule(
            rule=created_rule,
            workspace_id=workspace_ctx.workspace_id,
            overwrite_existing=rule_data.overwrite_existing_categories
        )
        created_rule.applied_count = applied_count
    
    return created_rule

The service call to apply_single_rule (backend/app/api/rules.py#L96-L107) ensures that rule changes take effect immediately rather than only applying to future transactions.

Preview Rules Without Persistence

The POST /api/rules/preview endpoint addresses a critical user need: testing rule logic before committing changes. This endpoint accepts a rule definition identical to the create payload but does not persist anything to the database.


# Example preview request

import requests

preview_payload = {
    "conditions_op": "any",
    "conditions": [
        {"field": "description", "op": "contains", "value": "Netflix"}
    ],
    "actions": [
        {"type": "category", "value": "Entertainment"}
    ],
    "is_active": True,
    "apply_to_existing": False,
    "limit": 10  # Restrict preview to N matching transactions

}

response = requests.post(
    "https://api.securo.finance/api/rules/preview",
    json=preview_payload,
    headers={"Authorization": "Bearer <TOKEN>"}
)

# Response includes matched transactions and proposed changes

print(response.json())

The preview logic (backend/app/api/rules.py#L13-L33) executes the rule's condition matching against actual transaction data but returns only a projection of what would change—no writes occur.

Export and Import Rule Sets

Data portability is essential for backup, migration, and sharing configurations. The rules engine API provides bidirectional JSON serialization.

Export Rules

The GET /api/rules/export endpoint generates a downloadable JSON file containing all rules in the workspace:


# backend/app/api/rules.py (simplified)

@router.get("/api/rules/export")
async def export_rules(
    workspace_ctx: WorkspaceContext = Depends(get_workspace_context),
    rule_service: RuleService = Depends(get_rule_service)
):
    """Export all workspace rules as JSON."""
    rules_data = await rule_service.export_rules(workspace_ctx.workspace_id)
    return Response(
        content=json.dumps(rules_data, indent=2, default=str),
        media_type="application/json",
        headers={"Content-Disposition": "attachment; filename=securo-rules.json"}
    )

Implementation at backend/app/api/rules.py#L38-L49.

Import Rules

The POST /api/rules/import endpoint accepts a previously exported JSON payload and recreates rules in the target workspace:

import json
import requests

with open("my-securo-rules.json") as f:
    rules_content = f.read()

import_payload = {
    "payload": rules_content,
    "overwrite": True  # Replace existing rules with same name

}

response = requests.post(
    "https://api.securo.finance/api/rules/import",
    json=import_payload,
    headers={"Authorization": "Bearer <TOKEN>"}
)

The import handler at backend/app/api/rules.py#L52-L73 validates the schema, handles duplicate detection based on the overwrite flag, and reports import statistics.

Rule Packs: Pre-Built Categorization Logic

Securo ships with rule packs—curated collections of rules for specific countries or financial domains. The API exposes endpoints to discover and install these packs.

List Available Packs

The GET /api/rules/packs endpoint enumerates installable rule packs with metadata (country code, description, rule count).

Install a Rule Pack

The POST /api/rules/packs/{pack_code}/install endpoint applies a complete rule set to the workspace. The implementation (backend/app/api/rules.py#L48-L70) optionally creates missing default categories referenced by the pack's rules:


# Example: Install Brazil-specific rules

response = requests.post(
    "https://api.securo.finance/api/rules/packs/BR/install",
    json={"create_missing_categories": True},
    headers={"Authorization": "Bearer <TOKEN>"}
)

This feature enables rapid onboarding for users in supported markets without requiring manual rule configuration.

Bulk Re-Application with Apply-All

The POST /api/rules/apply-all endpoint provides a nuclear option: re-run every active rule against every transaction in the workspace. This is essential after:

  • Bulk transaction imports
  • Rule pack installations
  • Changing category structures
  • Recovering from data inconsistencies

# Trigger full re-categorization

response = requests.post(
    "https://api.securo.finance/api/rules/apply-all",
    headers={"Authorization": "Bearer <TOKEN>"}
)

# Response typically includes statistics on matches and updates

print(response.json())

The endpoint at backend/app/api/rules.py#L78-L85 delegates to the rule service's bulk application logic, which processes rules in priority order and handles conflicts when multiple rules match the same transaction.

Rule Service: The Implementation Layer

The API layer in backend/app/api/rules.py is a thin wrapper around backend/app/services/rule_service.py. The service encapsulates:

Method Purpose
create_rule Persist new rule with validation and uniqueness checks
apply_single_rule Execute one rule against matching transactions ([rule_service.py](https://github.com/securo-finance/securo/blob/main/backend/app/services/rule_service.py))
preview_rule Simulate rule execution without persistence
export_rules Serialize workspace rules to portable JSON
import_rules Deserialize and validate rule imports with duplicate handling
install_rule_pack Expand pack templates into workspace rules
apply_all_rules Orchestrate bulk re-application with priority ordering

The service uses WorkspaceContext ([backend/app/core/workspace_context.py](https://github.com/securo-finance/securo/blob/main/backend/app/core/workspace_context.py)) to enforce multi-tenant isolation—every rule operation is scoped to the authenticated user's workspace.

Complete API Endpoint Reference

Endpoint Method Purpose
/api/rules GET List all workspace rules
/api/rules POST Create new rule with optional immediate application
/api/rules/{rule_id} PATCH Update existing rule
/api/rules/{rule_id} DELETE Remove a rule
/api/rules/preview POST Test rule logic without saving
/api/rules/export GET Download rules as JSON
/api/rules/import POST Upload and install rules from JSON
/api/rules/packs GET List available rule packs
/api/rules/packs/{pack_code}/install POST Install a rule pack
/api/rules/apply-all POST Re-run all active rules on all transactions

Summary

Securo's rules engine API provides a complete infrastructure for automated transaction categorization:

  • Rule CRUD with workspace isolation and immediate application to historic data
  • Safe experimentation through the preview endpoint
  • Data portability via JSON export/import
  • Accelerated setup through installable rule packs
  • Maintenance operations including bulk re-application

The API design separates HTTP concerns in backend/app/api/rules.py from business logic in backend/app/services/rule_service.py, enabling testable, maintainable code that scales with user demand.

Frequently Asked Questions

What is the difference between creating a rule and previewing a rule?

Creating a rule persists the rule definition to the database and optionally applies it to existing transactions. Previewing a rule executes the rule logic against actual transaction data but makes no changes—it's a read-only simulation for validation. Use preview to test conditions and actions before committing.

How do rule packs differ from individual rules?

Rule packs are pre-built collections of rules distributed with Securo for specific countries or use cases. Installing a pack creates multiple individual rules in your workspace. Packs provide sensible defaults for new users, while individual rules allow fine-grained customization.

What happens when I call apply-all?

The apply-all endpoint re-executes every active rule against every transaction in your workspace, in priority order. This is useful for maintaining consistency after bulk imports or rule changes. The operation is idempotent—running it multiple times produces the same result.

Can I undo a rule import or apply-all operation?

Securo does not provide automatic undo functionality. To revert changes, you must re-import a previous export or manually delete undesired rules. The export feature at backend/app/api/rules.py#L38-L49 enables you to create restore points before major operations.

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 →