Systems Library / Finance Automation / How to Automate Refund Processing Workflows
Finance Automation payments

How to Automate Refund Processing Workflows

Process refund requests with automated approval and payment execution.

Jay Banlasan

Jay Banlasan

The AI Systems Guy

Every refund I process runs through the same automate refund processing workflow system. No manual approvals for anything under a threshold. No copy-pasting between Stripe and a spreadsheet. One webhook triggers the whole chain.

I built this after watching a client's support team spend 40 minutes per refund chasing approvals through Slack. The fix took an afternoon to build and saves hours every week.

What You Need Before Starting

Step 1: Set Up the Refund Request Listener

Create a Flask endpoint that receives refund requests from your support tool or internal form:

from flask import Flask, request, jsonify
import stripe
import os

app = Flask(__name__)
stripe.api_key = os.getenv("STRIPE_SECRET_KEY")

AUTO_APPROVE_THRESHOLD = 5000  # $50.00 in cents

@app.route("/refund-request", methods=["POST"])
def handle_refund_request():
    data = request.json
    charge_id = data["charge_id"]
    amount = data.get("amount")  # None = full refund
    reason = data.get("reason", "requested_by_customer")

    charge = stripe.Charge.retrieve(charge_id)

    if (amount or charge.amount) <= AUTO_APPROVE_THRESHOLD:
        refund = process_refund(charge_id, amount, reason)
        return jsonify({"status": "auto_approved", "refund_id": refund.id})

    queue_for_approval(charge_id, amount, reason)
    return jsonify({"status": "pending_approval"})

Step 2: Build the Auto-Approve Logic

For refunds under your threshold, process them immediately:

def process_refund(charge_id, amount, reason):
    refund_params = {
        "charge": charge_id,
        "reason": reason,
    }
    if amount:
        refund_params["amount"] = amount

    refund = stripe.Refund.create(**refund_params)
    notify_team(refund, "auto_approved")
    log_refund(refund)
    return refund

Step 3: Build the Approval Queue

Refunds above the threshold go into a queue. I use a simple SQLite table:

import sqlite3
from datetime import datetime

def queue_for_approval(charge_id, amount, reason):
    conn = sqlite3.connect("refunds.db")
    conn.execute("""
        INSERT INTO pending_refunds (charge_id, amount, reason, requested_at, status)
        VALUES (?, ?, ?, ?, 'pending')
    """, (charge_id, amount, reason, datetime.now().isoformat()))
    conn.commit()
    conn.close()
    notify_team({"charge_id": charge_id, "amount": amount}, "needs_approval")

Step 4: Add the Approval Endpoint

When a manager approves, hit this endpoint:

@app.route("/approve-refund", methods=["POST"])
def approve_refund():
    data = request.json
    refund_id = data["pending_id"]

    conn = sqlite3.connect("refunds.db")
    row = conn.execute(
        "SELECT charge_id, amount, reason FROM pending_refunds WHERE id = ?",
        (refund_id,)
    ).fetchone()

    if not row:
        return jsonify({"error": "not_found"}), 404

    refund = process_refund(row[0], row[1], row[2])
    conn.execute(
        "UPDATE pending_refunds SET status = 'approved' WHERE id = ?",
        (refund_id,)
    )
    conn.commit()
    return jsonify({"status": "approved", "refund_id": refund.id})

Step 5: Add Notifications and Logging

Every refund, whether auto-approved or manual, gets logged and notified:

import requests

def notify_team(refund_data, status):
    webhook_url = os.getenv("SLACK_WEBHOOK_URL")
    message = f"Refund {status}: {refund_data}"
    requests.post(webhook_url, json={"text": message})

def log_refund(refund):
    conn = sqlite3.connect("refunds.db")
    conn.execute("""
        INSERT INTO refund_log (refund_id, charge_id, amount, status, processed_at)
        VALUES (?, ?, ?, ?, ?)
    """, (refund.id, refund.charge, refund.amount, refund.status, datetime.now().isoformat()))
    conn.commit()

What to Build Next

Add a daily summary report that shows total refunds processed, average time to resolution, and refund rate by product. That data tells you if you have a product problem or just normal churn.

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