How to Automate Expense Categorization with OpenClaw in Paradime
Feb 26, 2026
How to Automate Expense Categorization with Paradime, OpenClaw, and Google Sheets
Stop manually tagging spreadsheet rows. This guide walks you through a repeatable, outcome-driven workflow: read uncategorized transactions from a Google Sheet, classify them by expense category using OpenClaw's AI agent SDK, update the sheet automatically, and schedule everything to run daily with Paradime Bolt—zero human intervention required.
By the end of this article, you'll have a production-grade pipeline that measures uncategorized transactions, identifies the right expense categories (travel, software, meals, etc.), fixes the spreadsheet in place, and validates savings by logging every classification run.
What is Paradime?
Paradime is an all-in-one, AI-native platform that replaces dbt Cloud™ for analytics and data engineering teams. It provides a dbt™-native workspace where teams can develop, schedule, monitor, and debug data pipelines from a single interface.
Three core modules power the platform:
Module | What It Does |
|---|---|
Code IDE | AI-assisted dbt™ and Python development with inline lineage, data samples, and DinoAI copilot |
Bolt | Production scheduling, CI/CD, cron-based orchestration, Python script execution, and notifications |
Radar | FinOps dashboards for Snowflake and BigQuery cost monitoring |
For this tutorial, Bolt is the key module. Bolt lets you schedule any combination of dbt run, dbt test, and custom Python scripts on a cron cadence—complete with environment variable injection, Slack/email/MS Teams notifications, and AI-powered debugging for failed runs.
What is OpenClaw?
OpenClaw is an open-source, self-hosted AI agent framework. Unlike chat-only interfaces, OpenClaw agents can autonomously execute tasks—reading files, calling APIs, classifying data, and writing results back to external systems.
Key characteristics relevant to this build:
Python SDK (
pip install openclaw-python) with a simpleClientclass for chat completions and skill execution.API-key authentication via
OPENCLAW_API_KEYenvironment variable.Model-agnostic: route to Claude, GPT-4, local Ollama, or any OpenAI-compatible endpoint.
Skill system: Markdown-defined instructions that standardize how the agent handles specific task types.
For expense categorization, we'll use OpenClaw's chat_completion endpoint to classify transaction descriptions into predefined categories—with structured JSON output for deterministic parsing.
Architecture Overview
Before diving into code, here's how all the pieces connect:
Figure 1: End-to-end flow — Bolt triggers the Python script on a cron schedule, the script reads uncategorized rows from Google Sheets, classifies each using OpenClaw, and writes categories back.
Setup: openclaw-sdk + Google Sheets API
Step 1: Install Dependencies
Create a pyproject.toml in your dbt™ project root (Paradime Bolt uses Poetry for dependency management):
Step 2: Google Cloud Service Account
Go to the Google Cloud Console.
Create a project (or select an existing one).
Enable the Google Sheets API and Google Drive API.
Navigate to IAM & Admin → Service Accounts → Create a service account.
Generate a JSON key and download it.
Share your target Google Sheet with the service account email (e.g.,
expense-bot@your-project.iam.gserviceaccount.com).
Step 3: OpenClaw API Key
Open the OpenClaw dashboard → Settings → API Keys.
Click Generate New Key.
Copy and store the key securely.
Step 4: Configure Environment Variables in Paradime
Navigate to Settings → Workspaces → Environment Variables → Bolt Schedules in the Paradime UI, and add:
Key | Value |
|---|---|
| The full JSON contents of your Google service account key |
| Your OpenClaw API key (e.g., |
| The Google Sheet ID from the spreadsheet URL |
Figure 2: Environment variable flow — secrets are stored once in Paradime and injected securely at runtime.
The Classification Script
Create the file scripts/categorize_expenses.py in your dbt™ project:
How the Workflow Maps to the Four-Step Loop
Figure 3: The measure → identify → fix → validate loop runs every day on autopilot.
Environment Variables Reference
Variable | Required | Description |
|---|---|---|
| ✅ | Full JSON content of Google Cloud service account key. Must have Sheets + Drive API scopes. |
| ✅ | API key from OpenClaw dashboard (format: |
| ✅ | The Google Spreadsheet ID — the long string in the URL between |
Where to set them: In the Paradime UI, go to Settings → Workspaces → Environment Variables → Bolt Schedules section → Add New. Each variable is encrypted at rest and injected into the Bolt runtime.
Access in Python:
Bolt Schedule: Cron Daily
Now wire the script into Paradime Bolt so it runs automatically every day.
Option A: Schedules as Code (YAML)
Add this to your paradime_schedules.yml in the project root:
Important: The first command must be
poetry install— this creates the virtual environment and installs dependencies (gspread, openclaw-python, etc.) before your script runs.
Paradime auto-syncs paradime_schedules.yml from your default branch every 10 minutes. For immediate pickup, click Parse Schedules in the Bolt UI.
Option B: Bolt UI
Navigate to Bolt in the Paradime sidebar.
Click + New Schedule → + Create New Schedule.
Fill in:
Configure notifications (Slack, email, or MS Teams) for
failedandslaevents.Click Save.
Figure 4: The deployment flow — commit YAML to main, Bolt picks it up, and runs the pipeline daily.
Monitoring and Debugging
Once the schedule is live, Paradime provides three layers of observability:
1. Run History Dashboard
Navigate to Bolt → [your schedule] → Run History. You'll see:
Status: Success, Error, or Skipped for every execution.
Execution Time History: A 30-day chart showing duration trends, success/error rates, and total run count.
Trigger Source: Whether the run was scheduled (cron) or manually triggered.
2. Log Types for Failed Runs
When a run fails, click the Run ID to access three log levels:
Log Type | What It Shows | When to Use |
|---|---|---|
Summary Logs | DinoAI-generated overview of the failure with suggested fixes | First stop — quick triage |
Console Logs | Full stdout/stderr from the Python script | Finding the exact error message and traceback |
Debug Logs | System-level operations (git clone, poetry install, env setup) | Infrastructure issues |
3. Notifications
Configure alerts on three event types:
Failed: Script crashed or returned non-zero exit code.
SLA: Run exceeded
sla_minutesthreshold (15 minutes in our config).Success: Optional confirmation that the run completed.
Destinations: Email, Slack, and Microsoft Teams. Set these in the notifications block of your paradime_schedules.yml or via the Bolt UI.
4. Bolt System Alerts
Paradime also surfaces workspace-level issues automatically:
Bolt Parse Errors — YAML syntax issues in
paradime_schedules.ymlOOM Runs — Out-of-memory failures
Git Clone Failures — Branch not found or auth issues
24-Hour Run Timeouts — Runaway processes
Troubleshooting Common Issues
❌ google.auth.exceptions.DefaultCredentialsError
Cause: The GOOGLE_CREDENTIALS_JSON env var is missing, empty, or contains malformed JSON.
Fix:
Verify the variable exists in Settings → Environment Variables → Bolt Schedules.
Ensure the value is the raw JSON string (not a file path).
Test locally:
❌ gspread.exceptions.SpreadsheetNotFound
Cause: The service account doesn't have access to the sheet.
Fix: Share the Google Sheet with the service account email (visible in the JSON key under client_email). Grant Editor access.
❌ 401 Unauthorized from OpenClaw
Cause: Invalid or expired OPENCLAW_API_KEY.
Fix:
Regenerate the key in the OpenClaw dashboard → Settings → API Keys.
Update the value in Paradime Bolt environment variables.
Verify the key format starts with
sk-.
❌ json.JSONDecodeError During Classification
Cause: The LLM returned natural language instead of JSON.
Fix:
Set
temperature=0.0for deterministic responses (already in our script).Wrap the parse in a try/except with a fallback to
"miscellaneous"(already handled).If persistent, add a retry with a more explicit prompt or switch to a more instruction-following model.
❌ poetry install Fails in Bolt
Cause: Missing or malformed pyproject.toml.
Fix:
Ensure
pyproject.tomlis in the root of your dbt™ project (same level asdbt_project.yml).Verify it includes all required dependencies:
openclaw-python,gspread,google-auth.Check Bolt Debug Logs for the exact pip/poetry error.
❌ SLA Breach (Run Exceeds 15 Minutes)
Cause: Too many uncategorized rows, or OpenClaw API rate limiting.
Fix:
Add batching: process in chunks of 50 rows per run.
Use OpenClaw's rate limit headers (
X-RateLimit-Remaining) to throttle.Reduce the backlog by running the script manually once (
python scripts/categorize_expenses.py) before enabling the cron schedule.
Figure 5: Troubleshooting decision tree — match the error type to the fix, then re-run.
Wrapping Up
You now have a fully automated expense categorization pipeline that:
Measures — Reads your Google Sheet daily and identifies uncategorized transactions.
Identifies — Sends each transaction description to OpenClaw for AI-powered classification into categories like travel, software, meals, and more.
Fixes — Writes the category back to the spreadsheet in a single batch update.
Validates — Logs confidence scores, error counts, and elapsed time so you can audit every run.
The entire workflow runs hands-free on Paradime Bolt's cron scheduler, with Slack or email alerts if anything goes wrong.
What You Can Do Next
Add a confidence threshold: Only write back categories with confidence > 0.8; flag low-confidence rows for human review in a separate column.
Track spend trends in dbt™: Load the categorized sheet into your warehouse with a dbt™
source, then build models that aggregate spend by category and month.Expand categories dynamically: Store your category taxonomy in a separate sheet tab and read it at runtime—no code changes needed.
Multi-sheet support: Extend the script to iterate over multiple spreadsheets (e.g., per department) by reading a config from a
sheetstable.
Key Resources
Resource | Link |
|---|---|
Paradime Platform | |
Paradime Bolt Docs | |
Bolt Schedules as Code | https://docs.paradime.io/app-help/documentation/bolt/creating-schedules/schedules-as-code |
Bolt Environment Variables | |
OpenClaw Getting Started | |
Google Sheets API (Python) | https://developers.google.com/workspace/sheets/api/quickstart/python |
gspread Documentation |
Stop tagging expenses by hand. Let the machines do what they're good at—classifying text at scale—while you focus on what the numbers actually mean.

