How to Automate Law Firm Client Intake
Streamline client intake with automated forms, screening, and onboarding.
Jay Banlasan
The AI Systems Guy
Automating law firm client intake turns the messiest part of starting a new engagement into a smooth pipeline. I built this for a firm where intake meant phone tag, misplaced forms, and a week before the attorney had everything needed to start work. Now clients fill out a smart form, AI qualifies the case, and the attorney gets a complete intake package before the first call.
What You Need Before Starting
- Python 3.8+ with FastAPI
- Anthropic API key
- SQLite
- A web form or form builder
Step 1: Build the Intake Database
import sqlite3
from datetime import datetime
def init_intake_db(db_path="legal_intake.db"):
conn = sqlite3.connect(db_path)
conn.execute("""
CREATE TABLE IF NOT EXISTS intake_submissions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
full_name TEXT,
email TEXT,
phone TEXT,
case_type TEXT,
description TEXT,
urgency TEXT,
ai_qualification TEXT,
ai_score INTEGER,
status TEXT DEFAULT 'pending',
assigned_attorney TEXT,
submitted_at TEXT,
reviewed_at TEXT
)
""")
conn.commit()
conn.close()
Step 2: Build the Qualification Engine
import anthropic
from dotenv import load_dotenv
load_dotenv()
PRACTICE_AREAS = {
"personal_injury": {"min_value": 25000, "statute_check": True},
"business_litigation": {"min_value": 50000, "statute_check": True},
"family_law": {"min_value": 0, "statute_check": False},
"estate_planning": {"min_value": 0, "statute_check": False},
"employment": {"min_value": 10000, "statute_check": True},
}
def qualify_intake(submission):
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
system="""You are a legal intake specialist. Analyze the potential client's case and provide:
1. Case type classification
2. Preliminary merit assessment (strong/moderate/weak/insufficient info)
3. Estimated case value range if applicable
4. Statute of limitations concerns
5. Conflict check flags (names of opposing parties mentioned)
6. Key questions the attorney should ask in the first consultation
7. Qualification score 1-10
Return as structured text. Be objective. Flag insufficient information rather than guessing.""",
messages=[{
"role": "user",
"content": f"""New intake submission:
Name: {submission['full_name']}
Case Type: {submission['case_type']}
Urgency: {submission['urgency']}
Description: {submission['description']}"""
}]
)
return response.content[0].text
Step 3: Process Incoming Submissions
def process_intake(submission, db_path="legal_intake.db"):
qualification = qualify_intake(submission)
score = extract_score(qualification)
conn = sqlite3.connect(db_path)
conn.execute("""
INSERT INTO intake_submissions (full_name, email, phone, case_type, description,
urgency, ai_qualification, ai_score, submitted_at)
VALUES (?,?,?,?,?,?,?,?,?)
""", (submission["full_name"], submission["email"], submission["phone"],
submission["case_type"], submission["description"], submission["urgency"],
qualification, score, datetime.utcnow().isoformat()))
conn.commit()
conn.close()
if submission["urgency"] == "emergency" or score >= 8:
notify_attorney(submission, qualification, priority="high")
send_confirmation_email(submission["email"], submission["full_name"])
return {"qualification": qualification, "score": score}
def extract_score(qualification_text):
import re
match = re.search(r"(?:score|rating)[:\s]*(\d+)", qualification_text.lower())
return int(match.group(1)) if match else 5
Step 4: Build the Intake API
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class IntakeForm(BaseModel):
full_name: str
email: str
phone: str
case_type: str
description: str
urgency: str = "normal"
@app.post("/intake/submit")
def submit_intake(form: IntakeForm):
result = process_intake(form.dict())
return {
"status": "received",
"message": f"Thank you {form.full_name}. We will review your case and contact you within 24 hours."
}
@app.get("/intake/pending")
def get_pending():
conn = sqlite3.connect("legal_intake.db")
rows = conn.execute("""
SELECT id, full_name, case_type, urgency, ai_score, submitted_at
FROM intake_submissions WHERE status = 'pending'
ORDER BY ai_score DESC, submitted_at ASC
""").fetchall()
conn.close()
return [{"id": r[0], "name": r[1], "type": r[2], "urgency": r[3], "score": r[4], "submitted": r[5]} for r in rows]
Step 5: Attorney Review Dashboard
@app.get("/intake/{intake_id}")
def get_intake_detail(intake_id: int):
conn = sqlite3.connect("legal_intake.db")
row = conn.execute("SELECT * FROM intake_submissions WHERE id = ?", (intake_id,)).fetchone()
conn.close()
if not row:
return {"error": "Not found"}
columns = ["id", "full_name", "email", "phone", "case_type", "description",
"urgency", "ai_qualification", "ai_score", "status", "assigned_attorney",
"submitted_at", "reviewed_at"]
return dict(zip(columns, row))
@app.post("/intake/{intake_id}/assign")
def assign_attorney(intake_id: int, attorney: str):
conn = sqlite3.connect("legal_intake.db")
conn.execute(
"UPDATE intake_submissions SET assigned_attorney = ?, status = 'assigned', reviewed_at = ? WHERE id = ?",
(attorney, datetime.utcnow().isoformat(), intake_id)
)
conn.commit()
conn.close()
return {"status": "assigned", "attorney": attorney}
What to Build Next
Add conflict checking. Before qualifying a case, search your existing client database for the opposing party's name. Flag potential conflicts immediately so attorneys know before the consultation.
Related Reading
- AI in Legal and Compliance - AI applications in legal practice
- Automating Follow-Ups Without Being Annoying - client communication automation
- AI in CRM: Beyond Contact Storage - CRM automation patterns
Want this system built for your business?
Get a free assessment. We will map every system your business needs and show you the ROI.
Get Your Free Assessment