Systems Library / Operations & Admin / How to Automate Vendor Onboarding Workflows
Operations & Admin process workflow

How to Automate Vendor Onboarding Workflows

Streamline vendor onboarding with automated document collection and approval.

Jay Banlasan

Jay Banlasan

The AI Systems Guy

Vendor onboarding involves collecting documents from multiple people across multiple systems. I built a system to automate vendor onboarding workflows that tracks document submissions, sends reminders for missing items, and only activates the vendor once everything is complete.

No vendor gets paid until compliance is verified.

What You Need Before Starting

Step 1: Define Onboarding Requirements

VENDOR_REQUIREMENTS = {
    "standard": {
        "documents": [
            {"name": "W-9 Tax Form", "required": True, "category": "tax"},
            {"name": "Certificate of Insurance", "required": True, "category": "insurance"},
            {"name": "Signed MSA", "required": True, "category": "legal"},
            {"name": "Banking Information", "required": True, "category": "payment"},
            {"name": "Business License", "required": False, "category": "compliance"}
        ],
        "approvals": ["procurement", "legal", "finance"],
        "sla_days": 14
    }
}

Step 2: Create Vendor Onboarding Tracker

import sqlite3
from datetime import datetime, timedelta

def init_vendor_db(db_path="vendors.db"):
    conn = sqlite3.connect(db_path)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS vendor_onboarding (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            vendor_name TEXT,
            vendor_email TEXT,
            vendor_type TEXT,
            status TEXT DEFAULT 'pending_documents',
            initiated_at TEXT,
            deadline TEXT,
            activated_at TEXT
        )
    """)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS vendor_documents (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            vendor_id INTEGER,
            document_name TEXT,
            category TEXT,
            required INTEGER,
            received INTEGER DEFAULT 0,
            file_path TEXT,
            received_at TEXT
        )
    """)
    conn.commit()
    return conn

def start_vendor_onboarding(conn, vendor_name, vendor_email, vendor_type="standard"):
    requirements = VENDOR_REQUIREMENTS[vendor_type]
    deadline = (datetime.now() + timedelta(days=requirements["sla_days"])).strftime("%Y-%m-%d")

    cursor = conn.execute(
        "INSERT INTO vendor_onboarding (vendor_name, vendor_email, vendor_type, initiated_at, deadline) VALUES (?,?,?,?,?)",
        (vendor_name, vendor_email, vendor_type, datetime.now().isoformat(), deadline)
    )
    vendor_id = cursor.lastrowid

    for doc in requirements["documents"]:
        conn.execute(
            "INSERT INTO vendor_documents (vendor_id, document_name, category, required) VALUES (?,?,?,?)",
            (vendor_id, doc["name"], doc["category"], int(doc["required"]))
        )

    conn.commit()
    return vendor_id

Step 3: Track Document Submissions

def receive_document(conn, vendor_id, document_name, file_path):
    conn.execute("""
        UPDATE vendor_documents SET received=1, file_path=?, received_at=?
        WHERE vendor_id=? AND document_name=?
    """, (file_path, datetime.now().isoformat(), vendor_id, document_name))
    conn.commit()

    status = check_completion(conn, vendor_id)
    if status["all_required_received"]:
        conn.execute(
            "UPDATE vendor_onboarding SET status='pending_approval' WHERE id=?",
            (vendor_id,)
        )
        conn.commit()
    return status

def check_completion(conn, vendor_id):
    required_total = conn.execute(
        "SELECT COUNT(*) FROM vendor_documents WHERE vendor_id=? AND required=1",
        (vendor_id,)
    ).fetchone()[0]

    required_received = conn.execute(
        "SELECT COUNT(*) FROM vendor_documents WHERE vendor_id=? AND required=1 AND received=1",
        (vendor_id,)
    ).fetchone()[0]

    missing = conn.execute(
        "SELECT document_name FROM vendor_documents WHERE vendor_id=? AND required=1 AND received=0",
        (vendor_id,)
    ).fetchall()

    return {
        "all_required_received": required_received == required_total,
        "progress": f"{required_received}/{required_total}",
        "missing": [m[0] for m in missing]
    }

Step 4: Send Reminder Notifications

def send_vendor_reminders(conn):
    pending = conn.execute("""
        SELECT v.id, v.vendor_name, v.vendor_email, v.deadline
        FROM vendor_onboarding v
        WHERE v.status = 'pending_documents'
    """).fetchall()

    for vendor_id, name, email, deadline in pending:
        status = check_completion(conn, vendor_id)
        days_left = (datetime.strptime(deadline, "%Y-%m-%d") - datetime.now()).days

        if status["missing"] and days_left <= 7:
            missing_list = ", ".join(status["missing"])
            print(f"REMINDER to {name} ({email}): Missing documents: {missing_list}. Due in {days_left} days.")

Step 5: Activate Vendor

def activate_vendor(conn, vendor_id):
    status = check_completion(conn, vendor_id)
    if not status["all_required_received"]:
        return {"error": f"Cannot activate. Missing: {status['missing']}"}

    conn.execute(
        "UPDATE vendor_onboarding SET status='active', activated_at=? WHERE id=?",
        (datetime.now().isoformat(), vendor_id)
    )
    conn.commit()
    return {"status": "activated", "vendor_id": vendor_id}

What to Build Next

Add annual re-certification that checks if insurance certificates and licenses are still current. Vendors expire. Your tracking system should catch that before you have a compliance gap.

Related Reading

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

Related Systems