kite~/kite/docs/Self-Healing Billing Agent
v0.2.1
Guide

Self-Healing Billing Agent

Build an autonomous agent that reacts to Stripe payment failures with Kite — retries, customer notifications, and human escalation.

This guide walks through building an autonomous agent that listens to Stripe payment failures and automatically retries, notifies customers, and escalates to a human after repeated failures.

// 01What we're building

An agent that:

1. Receives payment_intent.payment_failed events from Stripe via Kite 2. Automatically retries the payment after a delay 3. Sends a customer notification on the first failure 4. Escalates to a human support queue after three consecutive failures

// 02Prerequisites

  • Kite installed and authenticated
  • A Stripe account with a test webhook endpoint
  • Node.js 20+ or Python 3.11+

// 03Step 1 — Create the Stripe endpoint

bash
kite endpoints create --source stripe

Add the relay URL to your Stripe dashboard under Developers → Webhooks. Subscribe to payment_intent.payment_failed. Paste the signing secret when prompted in the dashboard.

// 04Step 2 — Start streaming

bash
kite proxy --source stripe --target http://localhost:3001/webhook

// 05Step 3 — Write the agent handler

typescript
import express from "express";

const app = express();
app.use(express.json());

const failureCount = new Map<string, number>();

app.post("/webhook", async (req, res) => {
  const eventType = req.header("x-kite-event-type") ?? req.header("ce-type");
  const stripeEvent = req.body;

  if (eventType !== "com.stripe.payment_intent.payment_failed") {
    return res.sendStatus(200);
  }

  const paymentIntent = stripeEvent.data?.object ?? stripeEvent;
  const paymentIntentId = paymentIntent.id;
  const customer = paymentIntent.customer;
  const failures = (failureCount.get(paymentIntentId) ?? 0) + 1;
  failureCount.set(paymentIntentId, failures);

  if (failures === 1) {
    await notifyCustomer(customer, "We had trouble charging your card. We'll retry shortly.");
    await scheduleRetry(paymentIntentId, 30 * 60 * 1000); // 30 min
  } else if (failures === 2) {
    await notifyCustomer(customer, "Second payment attempt failed. Please update your payment method.");
    await scheduleRetry(paymentIntentId, 24 * 60 * 60 * 1000); // 24 hours
  } else {
    await escalateToSupport({ paymentIntentId, customer, failures });
    failureCount.delete(paymentIntentId);
  }

  res.sendStatus(200);
});

app.listen(3001);

// 06Step 4 — Run the agent

Trigger a test payment failure from the Stripe dashboard. Within milliseconds, your agent receives the CloudEvent and takes action — no polling, no exposed servers.

// 07Taking it further

  • Replace the in-memory Map with a database for persistence across restarts
  • Use kite listen --socket /tmp/kite.sock --source stripe to feed events into a local agent loop
  • Run another kite proxy or kite stream process for each additional source you want to handle

This pattern — a Kite listener feeding a local agent — is how we recommend building reactive, event-driven autonomous agents.