Autonomous agents are most useful when they react to real-world events without human intervention. In this guide, we'll build a self-healing billing agent that listens to Stripe payment failures via Kite and automatically takes corrective action.
What We're Building
An agent that:
1. Receives payment_intent.payment_failed events from Stripe via Kite. 2. Automatically retries the payment after a short delay. 3. Sends a friendly customer notification on the first failure. 4. Escalates to a human support queue after three consecutive failures.
Prerequisites
- •A Kite account (free tier works)
- •A Stripe account with a webhook endpoint configured
- •Node.js 20+ or Python 3.11+
Step 1 — Install and Authenticate Kite
curl -sSL https://getkite.sh/install | sh kite auth login
After login, grab your endpoint token from the dashboard. You'll use it to scope which events your agent receives.
Step 2 — Configure the Stripe Webhook
In your Stripe dashboard, create a webhook endpoint pointing at your Kite relay URL:
https://relay.getkite.sh/hooks/<your-endpoint-token>
Subscribe to the payment_intent.payment_failed event type. Kite will automatically verify the Stripe-Signature header using your signing secret — set it in your Kite dashboard under Endpoint → Sources → Stripe.
Step 3 — Start the Listener
kite listen stripe --forward http://localhost:3001/webhook
This opens a WebSocket to the relay and forwards verified Stripe events to your local server.
Step 4 — Write the Agent Logic
Here's a minimal Node.js handler:
import express from "express";
const app = express();
app.use(express.json());
const failureCount = new Map<string, number>();
app.post("/webhook", async (req, res) => {
const event = req.body; // CloudEvent envelope
if (event.type !== "com.stripe.payment_intent.payment_failed") {
return res.sendStatus(200);
}
const { id: paymentIntentId, customer } = event.data;
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, delayMs: 30 * 60 * 1000); // 30 min
} else if (failures === 2) {
await notifyCustomer(customer, "Second payment attempt failed. Please update your payment method.");
await scheduleRetry(paymentIntentId, delayMs: 24 * 60 * 60 * 1000); // 24 hours
} else {
await escalateToSupport({ paymentIntentId, customer, failures });
failureCount.delete(paymentIntentId);
}
res.sendStatus(200);
});
app.listen(3001);Step 5 — Run the Agent
Start your local server, then in a separate terminal:
kite listen stripe --forward http://localhost:3001/webhook
Trigger a test payment failure from the Stripe dashboard. Within milliseconds, your agent receives the CloudEvent, increments the failure count, and takes action — no polling, no webhook servers exposed to the internet.
Taking It Further
- •Persistent state: Replace the in-memory
Mapwith a database so the agent survives restarts. - •OpenClaw integration: Use
kite listen --sink openclawto feed events directly into an OpenClaw agent loop. - •Multi-source: Add
kite listen githubin the same terminal session to handle both Stripe and GitHub events in one stream.
This pattern — a lightweight Kite listener feeding a local agent — is how we recommend building reactive, event-driven agents. No infrastructure, no polling, just clean real-time events.