Skip to content
Learn Agentic AI
Learn Agentic AI14 min read2 views

AI Agent for Fundraising Campaigns: Progress Tracking, Donor Communication, and Impact Reports

Build an AI agent that manages fundraising campaigns with real-time progress tracking, segmented donor communication, milestone notifications, and automated impact reporting for nonprofits.

From Spreadsheets to Intelligent Campaign Management

Fundraising campaigns depend on three things: knowing where you stand against your goal, communicating the right message to the right donors, and demonstrating impact after the campaign ends. An AI fundraising agent automates all three: real-time dashboards, segmented donor outreach, milestone notifications, and impact reports that connect donations to outcomes.

Campaign and Donor Data Models

from dataclasses import dataclass, field
from datetime import datetime, date, timedelta
from typing import Optional
from enum import Enum
from uuid import uuid4


class DonorSegment(Enum):
    MAJOR_DONOR = "major_donor"
    MID_LEVEL = "mid_level"
    GRASSROOTS = "grassroots"
    FIRST_TIME = "first_time"
    LAPSED = "lapsed"


@dataclass
class Campaign:
    campaign_id: str = field(default_factory=lambda: str(uuid4()))
    name: str = ""
    goal_amount: float = 0.0
    raised_amount: float = 0.0
    donor_count: int = 0
    start_date: date = field(default_factory=date.today)
    end_date: date = field(
        default_factory=lambda: date.today() + timedelta(days=30))
    milestones: list[float] = field(
        default_factory=lambda: [25.0, 50.0, 75.0, 100.0])
    milestones_reached: list[float] = field(default_factory=list)
    impact_metrics: dict = field(default_factory=dict)


@dataclass
class CampaignDonor:
    donor_id: str = field(default_factory=lambda: str(uuid4()))
    name: str = ""
    email: str = ""
    segment: DonorSegment = DonorSegment.GRASSROOTS
    total_given_campaign: float = 0.0
    has_been_thanked: bool = False


@dataclass
class CampaignGift:
    gift_id: str = field(default_factory=lambda: str(uuid4()))
    campaign_id: str = ""
    amount: float = 0.0
    gift_date: date = field(default_factory=date.today)
    is_matching: bool = False

Campaign Progress Tracking

The agent monitors campaign progress in real time and detects when milestones are reached.

flowchart TD
    START["AI Agent for Fundraising Campaigns: Progress Trac…"] --> A
    A["From Spreadsheets to Intelligent Campai…"]
    A --> B
    B["Campaign and Donor Data Models"]
    B --> C
    C["Campaign Progress Tracking"]
    C --> D
    D["Donor Segmentation"]
    D --> E
    E["Impact Reporting"]
    E --> F
    F["Assembling the Fundraising Agent"]
    F --> G
    G["FAQ"]
    G --> DONE["Key Takeaways"]
    style START fill:#4f46e5,stroke:#4338ca,color:#fff
    style DONE fill:#059669,stroke:#047857,color:#fff
from agents import function_tool

campaigns_db: dict[str, Campaign] = {}
campaign_donors: dict[str, list[CampaignDonor]] = {}
campaign_gifts: list[CampaignGift] = []


@function_tool
async def get_campaign_dashboard(campaign_id: str) -> dict:
    """Get real-time campaign progress dashboard."""
    campaign = campaigns_db.get(campaign_id)
    if not campaign:
        return {"error": "Campaign not found"}

    pct = (campaign.raised_amount / campaign.goal_amount * 100
           if campaign.goal_amount > 0 else 0)
    days_left = (campaign.end_date - date.today()).days
    elapsed = max((date.today() - campaign.start_date).days, 1)
    daily_rate = campaign.raised_amount / elapsed
    projected = daily_rate * (campaign.end_date - campaign.start_date).days

    new_milestones = [m for m in campaign.milestones
                      if pct >= m and m not in campaign.milestones_reached]
    campaign.milestones_reached.extend(new_milestones)

    return {
        "campaign": campaign.name,
        "raised": campaign.raised_amount,
        "goal": campaign.goal_amount,
        "percent": round(pct, 1),
        "days_remaining": max(days_left, 0),
        "on_track": projected >= campaign.goal_amount,
        "new_milestones": new_milestones,
    }

Donor Segmentation

Segment donors so the agent can tailor messaging to each group.

@function_tool
async def segment_campaign_donors(campaign_id: str) -> dict:
    """Segment donors for targeted campaign communication."""
    donors = campaign_donors.get(campaign_id, [])
    if not donors:
        return {"error": "No donors found for this campaign"}

    segments = {}
    for donor in donors:
        seg = donor.segment.value
        if seg not in segments:
            segments[seg] = {"count": 0, "total_raised": 0.0}
        segments[seg]["count"] += 1
        segments[seg]["total_raised"] += donor.total_given_campaign

    unthanked = [d for d in donors
                 if d.total_given_campaign > 0 and not d.has_been_thanked]

    return {
        "segments": segments,
        "unthanked_count": len(unthanked),
        "total_donors": len(donors),
    }


@function_tool
async def record_campaign_gift(
    campaign_id: str,
    donor_name: str,
    donor_email: str,
    amount: float,
    is_matching: bool = False,
    dedication: str = "",
) -> dict:
    """Record a new gift to a campaign and update progress."""
    campaign = campaigns_db.get(campaign_id)
    if not campaign:
        return {"error": "Campaign not found"}

    gift = CampaignGift(
        campaign_id=campaign_id,
        amount=amount,
        is_matching=is_matching,
        dedication=dedication,
    )
    campaign_gifts.append(gift)

    campaign.raised_amount += amount
    campaign.donor_count += 1

    pct = campaign.raised_amount / campaign.goal_amount * 100

    return {
        "status": "recorded",
        "gift_id": gift.gift_id,
        "donor": donor_name,
        "amount": amount,
        "campaign_total": campaign.raised_amount,
        "percent_of_goal": round(pct, 1),
        "is_matching": is_matching,
    }

Impact Reporting

After a campaign ends, the agent generates impact reports that connect donations to outcomes.

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

@function_tool
async def generate_impact_report(campaign_id: str) -> dict:
    """Generate an impact report for a completed campaign."""
    campaign = campaigns_db.get(campaign_id)
    if not campaign:
        return {"error": "Campaign not found"}

    gifts = [g for g in campaign_gifts if g.campaign_id == campaign_id]
    gift_amounts = [g.amount for g in gifts]
    avg_gift = sum(gift_amounts) / len(gift_amounts) if gift_amounts else 0
    matching_total = sum(g.amount for g in gifts if g.is_matching)

    return {
        "campaign": campaign.name,
        "goal": campaign.goal_amount,
        "total_raised": campaign.raised_amount,
        "total_donors": campaign.donor_count,
        "total_gifts": len(gifts),
        "average_gift": round(avg_gift, 2),
        "matching_funds": matching_total,
        "impact_metrics": campaign.impact_metrics,
        "milestones_reached": campaign.milestones_reached,
    }

Assembling the Fundraising Agent

from agents import Agent, Runner

fundraising_agent = Agent(
    name="Fundraising Campaign Agent",
    instructions="""You are a fundraising campaign manager agent.

1. Track campaign progress in real time against goals
2. Record gifts and update totals with milestone detection
3. Segment donors for targeted communication
4. Identify unthanked donors for follow-up
5. Generate impact reports after campaigns close
6. Flag campaigns behind pace with recovery ideas
7. Major donors get personal outreach, grassroots get
   community-focused messaging
8. Always express gratitude — every gift matters""",
    tools=[
        get_campaign_dashboard,
        segment_campaign_donors,
        record_campaign_gift,
        generate_impact_report,
    ],
)

result = Runner.run_sync(
    fundraising_agent,
    "Give me a dashboard update on our Spring campaign (ID: spring-2026). "
    "We need to know if we are on track and which donor segments "
    "need outreach. Also identify anyone who has not been thanked yet.",
)
print(result.final_output)

FAQ

How does the agent determine if a campaign is on track?

The agent calculates a daily giving rate by dividing total raised by the number of days elapsed. It then projects the total by multiplying the daily rate by the full campaign duration. If the projected total meets or exceeds the goal, the campaign is marked as on track. This simple linear projection works well for most campaigns, though giving-day events may need different models that account for last-day surges.

How should the agent handle matching gift campaigns?

When recording a gift, the agent accepts an is_matching flag. Matching gifts are tracked separately in the impact report so the organization can show donors how their individual gifts were amplified. The agent can also proactively inform donors about active matching opportunities by checking if a matching gift program is associated with the campaign.

What makes a good impact report?

A good impact report connects dollars to outcomes. Instead of just saying "$50,000 raised," it should say "$50,000 raised, providing 10,000 meals to families in our community." The impact_metrics field in the campaign model stores these conversion ratios (for example, $5 per meal), and the report multiplies total raised by the ratio to produce concrete outcome numbers that donors can connect with emotionally.


#Fundraising #NonprofitAI #CampaignManagement #AgenticAI #Python #LearnAI #AIEngineering

Share
C

Written by

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.

Related Articles You May Like

AI Interview Prep

7 AI Coding Interview Questions From Anthropic, Meta & OpenAI (2026 Edition)

Real AI coding interview questions from Anthropic, Meta, and OpenAI in 2026. Includes implementing attention from scratch, Anthropic's progressive coding screens, Meta's AI-assisted round, and vector search — with solution approaches.

Learn Agentic AI

Fine-Tuning LLMs for Agentic Tasks: When and How to Customize Foundation Models

When fine-tuning beats prompting for AI agents: dataset creation from agent traces, SFT and DPO training approaches, evaluation methodology, and cost-benefit analysis for agentic fine-tuning.

AI Interview Prep

7 Agentic AI & Multi-Agent System Interview Questions for 2026

Real agentic AI and multi-agent system interview questions from Anthropic, OpenAI, and Microsoft in 2026. Covers agent design patterns, memory systems, safety, orchestration frameworks, tool calling, and evaluation.

Learn Agentic AI

Building a Multi-Agent Data Pipeline: Ingestion, Transformation, and Analysis Agents

Build a three-agent data pipeline with ingestion, transformation, and analysis agents that process data from APIs, CSVs, and databases using Python.

Learn Agentic AI

Adaptive Thinking in Claude 4.6: How AI Agents Decide When and How Much to Reason

Technical exploration of adaptive thinking in Claude 4.6 — how the model dynamically adjusts reasoning depth, its impact on agent architectures, and practical implementation patterns.

Learn Agentic AI

How NVIDIA Vera CPU Solves the Agentic AI Bottleneck: Architecture Deep Dive

Technical analysis of NVIDIA's Vera CPU designed for agentic AI workloads — why the CPU is the bottleneck, how Vera's architecture addresses it, and what it means for agent performance.