By Sagar Shankaran, Founder of CallSphere
Learn how to build an AI agent that searches grant databases, matches nonprofits with eligible funding opportunities, tracks deadlines, and provides application guidance.
Key takeaways
Nonprofits leave billions of dollars in grant funding on the table every year — not because they are unqualified, but because they never find the opportunities. Grant research is tedious: sifting through hundreds of foundations, government programs, and corporate giving portals, each with different eligibility criteria, application formats, and deadlines. Small nonprofits without dedicated grant writers are at the greatest disadvantage.
An AI grant research agent can continuously scan funding databases, match opportunities against an organization's profile, track deadlines, and provide structured guidance for applications. This levels the playing field for organizations that cannot afford a full-time development officer.
Define the structures for grant opportunities and the nonprofit's profile.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
flowchart LR
CALLER(["Donor or Volunteer"])
subgraph TEL["Telephony"]
SIP["Twilio SIP and PSTN"]
end
subgraph BRAIN["Nonprofit AI Agent"]
STT["Streaming STT<br/>Deepgram or Whisper"]
NLU{"Intent and<br/>Entity Extraction"}
TOOLS["Tool Calls"]
TTS["Streaming TTS<br/>ElevenLabs or Rime"]
end
subgraph DATA["Live Data Plane"]
CRM[("CRM and Notes")]
CAL[("Calendar and<br/>Schedule")]
KB[("Knowledge Base<br/>and Policies")]
end
subgraph OUT["Outcomes"]
O1(["Donation pledge captured"])
O2(["Volunteer slot booked"])
O3(["Program lead handoff"])
end
CALLER --> SIP --> STT --> NLU
NLU -->|Lookup| TOOLS
TOOLS <--> CRM
TOOLS <--> CAL
TOOLS <--> KB
NLU --> TTS --> SIP --> CALLER
NLU -->|Resolved| O1
NLU -->|Schedule| O2
NLU -->|Escalate| O3
style CALLER fill:#f1f5f9,stroke:#64748b,color:#0f172a
style NLU fill:#4f46e5,stroke:#4338ca,color:#fff
style O1 fill:#059669,stroke:#047857,color:#fff
style O2 fill:#0ea5e9,stroke:#0369a1,color:#fff
style O3 fill:#f59e0b,stroke:#d97706,color:#1f2937
from dataclasses import dataclass, field
from datetime import date, timedelta
from typing import Optional
from enum import Enum
from uuid import uuid4
class FocusArea(Enum):
EDUCATION = "education"
HEALTH = "health"
ENVIRONMENT = "environment"
ARTS = "arts"
HOUSING = "housing"
YOUTH = "youth"
WORKFORCE = "workforce"
@dataclass
class GrantOpportunity:
grant_id: str = field(default_factory=lambda: str(uuid4()))
title: str = ""
funder: str = ""
focus_areas: list[FocusArea] = field(default_factory=list)
amount_min: float = 0.0
amount_max: float = 0.0
deadline: Optional[date] = None
geographic_restrictions: list[str] = field(default_factory=list)
description: str = ""
match_score: float = 0.0
@dataclass
class NonprofitProfile:
org_name: str = ""
ein: str = ""
focus_areas: list[FocusArea] = field(default_factory=list)
annual_budget: float = 0.0
year_founded: int = 2020
state: str = ""
has_501c3: bool = True
The agent searches a grant database and calculates a match score based on alignment between the grant's criteria and the organization's profile.
from agents import function_tool
grants_db: list[GrantOpportunity] = []
@function_tool
async def search_grants(
focus_area: str = "",
grant_type: str = "",
min_amount: float = 0,
max_amount: float = 0,
state: str = "",
deadline_within_days: int = 90,
) -> dict:
"""Search for grant opportunities matching specified criteria."""
results = []
today = date.today()
deadline_cutoff = today + timedelta(days=deadline_within_days)
for grant in grants_db:
if grant.deadline and grant.deadline < today:
continue
if grant.deadline and grant.deadline > deadline_cutoff:
continue
if focus_area:
area = FocusArea(focus_area)
if area not in grant.focus_areas:
continue
if grant_type:
if grant.grant_type.value != grant_type:
continue
if min_amount and grant.amount_max < min_amount:
continue
if max_amount and grant.amount_min > max_amount:
continue
if state and grant.geographic_restrictions:
if state not in grant.geographic_restrictions:
continue
results.append({
"grant_id": grant.grant_id,
"title": grant.title,
"funder": grant.funder,
"type": grant.grant_type.value,
"amount_range": f"${grant.amount_min:,.0f} - "
f"${grant.amount_max:,.0f}",
"deadline": str(grant.deadline) if grant.deadline else "Rolling",
"focus_areas": [a.value for a in grant.focus_areas],
"description": grant.description[:200],
})
results.sort(
key=lambda x: x["deadline"] if x["deadline"] != "Rolling" else "9999"
)
return {"grants": results, "total_found": len(results)}
@function_tool
async def match_grants_to_profile(
org_focus_areas: list[str],
org_budget: float,
org_state: str,
org_year_founded: int,
has_501c3: bool = True,
) -> dict:
"""Match available grants to an organization profile with
scoring based on alignment."""
today = date.today()
matches = []
org_areas = {FocusArea(a) for a in org_focus_areas}
for grant in grants_db:
if grant.deadline and grant.deadline < today:
continue
score = 0.0
area_overlap = len(set(grant.focus_areas) & org_areas)
if area_overlap == 0:
continue
score += min(area_overlap * 20, 40)
if not grant.geographic_restrictions:
score += 15
elif org_state in grant.geographic_restrictions:
score += 20
if has_501c3:
score += 10
if today.year - org_year_founded >= 3:
score += 10
if score >= 30:
matches.append({
"title": grant.title, "funder": grant.funder,
"match_score": score,
"amount": f"${grant.amount_min:,.0f}-${grant.amount_max:,.0f}",
"deadline": str(grant.deadline) if grant.deadline else "Rolling",
})
matches.sort(key=lambda x: x["match_score"], reverse=True)
return {"matches": matches[:10], "total_matches": len(matches)}
@function_tool
async def get_upcoming_deadlines(days_ahead: int = 30) -> dict:
"""Get grants with deadlines approaching within a window."""
today = date.today()
cutoff = today + timedelta(days=days_ahead)
upcoming = []
for grant in grants_db:
if grant.deadline and today <= grant.deadline <= cutoff:
days_left = (grant.deadline - today).days
urgency = "critical" if days_left <= 7 else (
"soon" if days_left <= 14 else "upcoming"
)
upcoming.append({
"title": grant.title,
"funder": grant.funder,
"deadline": str(grant.deadline),
"days_remaining": days_left,
"urgency": urgency,
})
upcoming.sort(key=lambda x: x["days_remaining"])
return {"upcoming_deadlines": upcoming, "count": len(upcoming)}
from agents import Agent, Runner
grant_agent = Agent(
name="Grant Research Agent",
instructions="""You are a grant research agent for nonprofits.
Your responsibilities:
1. Search grant databases by focus area, type, and location
2. Match grants to organization profiles with scoring
3. Track upcoming deadlines and flag urgent ones
4. Prioritize grants with the highest match scores
5. Flag grants closing within 7 days as critical
6. For federal grants, note SAM.gov registration requirement
7. Never guarantee funding — present opportunities accurately
8. Suggest contacting the program officer before applying""",
tools=[
search_grants,
match_grants_to_profile,
get_upcoming_deadlines,
],
)
result = Runner.run_sync(
grant_agent,
"We are a youth education nonprofit in California with a $300K "
"annual budget, founded in 2019. Find grants that match our "
"profile and tell us about upcoming deadlines.",
)
print(result.final_output)
The match score is calculated on a 100-point scale across four dimensions: focus area alignment (up to 40 points based on overlap between the grant's focus areas and the organization's mission), budget fit (20 points if the organization falls within the grant's target budget range), geographic eligibility (20 points for state match), and basic eligibility (20 points for 501c3 status and organizational age). Only grants scoring 30 or above are returned.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
The agent provides application checklists and tips, but writing a compelling grant narrative requires deep knowledge of the organization's programs and impact data. The agent can generate draft outlines and suggest key talking points based on the funder's priorities, but the final narrative should be reviewed and personalized by someone who knows the organization intimately.
In production, integrate with APIs from Grants.gov for federal opportunities, Foundation Directory Online for private foundations, and state-specific portals. Run a scheduled job that fetches new grants daily, deduplicates entries, and removes expired listings. The agent always checks the deadline against today's date before presenting an opportunity.
#GrantResearch #NonprofitFunding #AIForGood #AgenticAI #Python #LearnAI #AIEngineering

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
The 2026 desktop AI agent landscape — ServiceNow Project Arc, Anthropic Claude offerings, OpenAI agents, and Google Mariner. A buyer's map.
Step-by-step build of a working agent with the OpenAI Agents SDK — Agent class, tools, handoffs, tracing — plus an eval pipeline that catches regressions before merge.
An agentic-AI perspective on Anthropic Skills system, covering orchestration patterns, tool use, and how agent tooling fits production agent stacks.
Enterprise CIO Guide perspective on Comet's general-availability launch put an agentic browser in front of millions of consumers, and it works better than the demos suggested.
Enterprise CIO Guide perspective on Harvey AI's enterprise rollout numbers show legal agents have moved past the pilot stage at AmLaw 100 firms.
Enterprise CIO Guide perspective on Hippocratic AI's deployment numbers show healthcare voice agents are moving from pilot to production across major US health systems.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco