Building an AI-Powered Receipt Capture Bot for Discord

February 4, 2026 • 12 min read • Technical Guide

Discord Claude Vision Firebase TypeScript OpenRouter

I've been running multiple small businesses and the most tedious part has always been expense tracking. Taking photos of receipts, manually entering data, categorizing transactions — it's death by a thousand paper cuts.

So I built a system where I can just snap a photo, send it to my Discord bot, and have it automatically extract the data and save it to my finance dashboard. Here's exactly how I did it.

The End Result

Before diving into the technical details, here's what the finished system looks like:

User sends receipt photo to Discord ↓ Bot analyzes image with Claude Vision ↓ Extracts: merchant, date, amount, description ↓ Suggests category based on keywords ↓ User confirms or corrects ↓ Transaction saved to Firestore ↓ Appears on web dashboard instantly

The whole process takes about 10 seconds from photo to saved transaction.

Architecture Overview

┌─────────────┐ ┌──────────────┐ ┌─────────────────┐ │ Discord │────▶│ Bot Server │────▶│ Claude Vision │ │ (User) │ │ (Gateway) │ │ (via OpenRouter)│ └─────────────┘ └──────────────┘ └─────────────────┘ │ ▼ ┌──────────────┐ ┌─────────────────┐ │ Firestore │◀───▶│ Dashboard │ │ Database │ │ (Web App) │ └──────────────┘ └─────────────────┘

Part 1: Bot Framework Setup

1 Choose Your Framework

I'm using Clawdbot, an open-source bot framework that supports Discord, Slack, and other platforms. The key feature I needed was the skill system that lets you define custom behaviors.

# Clone and install
git clone https://github.com/clawdbot/clawdbot.git
cd clawdbot
pnpm install

# Run the setup wizard
pnpm clawdbot onboard

2 Configure Discord

Create a Discord application at discord.com/developers:

  1. Create New Application
  2. Go to Bot → Add Bot
  3. Enable "Message Content Intent" (required to read message text)
  4. Copy the bot token

Add the bot to your server using OAuth2 URL Generator with bot scope and appropriate permissions (Send Messages, Read Message History, Add Reactions).

3 Use OpenRouter for Better Rate Limits

Important: Direct Anthropic API has strict rate limits (30K tokens/min for Sonnet). OpenRouter provides the same Claude models with much higher limits and you only pay for what you use.

Sign up at openrouter.ai, create an API key, and configure your bot:

{
  "agents": {
    "defaults": {
      "model": {
        "primary": "openrouter/anthropic/claude-sonnet-4",
        "fallbacks": ["openrouter/anthropic/claude-3.5-haiku"]
      }
    }
  }
}

Part 2: The Receipt Capture Skill

The skill system lets you define custom behaviors with trigger phrases and instructions. Here's the core of the receipt capture skill:

Skill Definition (SKILL.md)

---
name: receipt-capture
description: "Capture receipts and screenshots to add transactions."
metadata: {
  "triggers": ["add receipt", "log receipt", "log this expense"]
}
---

# Receipt Capture

## When to Use
- User sends an image attachment with a receipt
- User says "add this receipt" or "log this expense"

## Workflow

1. Analyze the image using vision capabilities
2. Extract: merchant, date, amount, description
3. Suggest category based on keywords
4. Ask user to confirm
5. Save to database

Category Matching Logic

The bot uses keyword matching to suggest categories:

const CATEGORY_KEYWORDS = {
  software: ['software', 'subscription', 'api', 'saas', 'cloud'],
  supplies: ['supplies', 'materials', 'equipment', 'tools'],
  meals: ['food', 'restaurant', 'coffee', 'lunch', 'dinner'],
  travel: ['uber', 'lyft', 'flight', 'hotel', 'airbnb'],
  advertising: ['ads', 'marketing', 'meta', 'google', 'facebook']
};

function suggestCategory(merchant, description) {
  const text = `${merchant} ${description}`.toLowerCase();
  for (const [category, keywords] of Object.entries(CATEGORY_KEYWORDS)) {
    if (keywords.some(kw => text.includes(kw))) {
      return category;
    }
  }
  return 'general';
}

Handling Edge Cases

Real-world receipts are messy. The skill handles common issues:

Part 3: Firebase/Firestore Setup

Database Schema

// transactions collection
{
  id: string,
  date: string,           // "2026-02-04"
  description: string,    // "Google LLC - Services"
  amount: number,         // 93.60
  type: "expense",
  category: string,       // "software"
  entity: string,         // "business-name"
  source: "receipt-capture",
  metadata: {
    merchant: string,
    capturedAt: timestamp,
    originalCurrency: string
  }
}

Security Rules

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /transactions/{transactionId} {
      allow read, write: if request.auth != null;
    }
  }
}

Part 4: The Confirmation Flow

Never auto-save without confirmation. The bot always shows extracted data and waits for user approval:

🎯 Analyzing receipt...

**Extracted Data:**
- Merchant: Google LLC
- Date: April 1, 2024
- Amount: CA$93.60
- Description: Google services payment

**Suggested:**
- Category: software
- Entity: business-name

Does this look correct? Reply **confirm** to save,
or tell me what to change! 🏕️

Users can then:

Part 5: The Web Dashboard

Transactions appear instantly on a simple web dashboard using Firebase's real-time listeners:

import { onSnapshot, query, orderBy } from 'firebase/firestore';

const q = query(
  collection(db, 'transactions'),
  orderBy('date', 'desc')
);

onSnapshot(q, (snapshot) => {
  const transactions = snapshot.docs.map(doc => ({
    id: doc.id,
    ...doc.data()
  }));
  renderTransactions(transactions);
});

Cost Breakdown

Component Cost
OpenRouter (Claude Sonnet) ~$3/million input tokens
OpenRouter (Claude Haiku) ~$0.25/million input tokens
Firebase Firestore Free tier: 50K reads, 20K writes/day
Firebase Hosting Free tier: 10GB storage
Estimated Monthly (light use) $5-15/month

Lessons Learned

1. Rate Limits Are Real

I hit Anthropic's rate limits immediately with the direct API. OpenRouter solved this completely. Don't assume you'll stay under limits.

2. Always Confirm Before Saving

OCR isn't perfect. Even Claude Vision occasionally misreads amounts or dates. The confirmation step has saved me from many bad entries.

3. Keep Categories Simple

Started with 20+ categories. Now I use 8. Fewer categories = faster categorization = actually using the system.

4. Mobile-First Matters

90% of my receipts come from my phone. The Discord mobile app works great for this - snap, send, confirm, done.

What's Next

Currently exploring:

The full code is available on GitHub. The skill system is part of the open-source Clawdbot framework at github.com/clawdbot/clawdbot.

Resources

Have questions or built something similar? Reach out on Twitter or get in touch.