Most SaaS teams find out about failed payments the same way they find out about churn: too late. A customer’s card declines on renewal, the dunning emails go ignored for a week, and the account quietly lapses. Stripe has all the data to catch this in real time, but nobody is watching the dashboard at 2 AM on a Saturday.
OpenClaw changes that. By connecting Stripe to your OpenClaw agent through a custom skill, you get a payment monitoring system that runs 24/7 and reports to you in Telegram, Slack, or WhatsApp. Failed charges, new disputes, subscription cancellations, daily revenue summaries — your agent watches Stripe and tells you what matters.
This guide covers the full setup: getting your Stripe API keys, creating a restricted key scoped for monitoring, writing the OpenClaw skill file, configuring webhooks for real-time alerts, and setting up scheduled reports. If OpenClaw is already running, expect about 25 minutes from start to finish.
What You Can Monitor
Once connected, your OpenClaw agent becomes a real-time financial watchdog for your Stripe account. Here is what it handles out of the box:
- Payment failure alerts — get notified the moment a charge fails, with the customer name, amount, and failure reason
- Subscription churn tracking — know immediately when a customer cancels or a subscription lapses
- Dispute and chargeback notifications — catch disputes early enough to respond within Stripe’s deadline
- Daily and weekly revenue summaries — MRR snapshots, net revenue, and refund totals delivered on schedule
- Dunning status updates — track which failed payments recovered after retry and which need manual intervention
The agent uses Stripe’s REST API with a restricted key that has read-only access. No payment processing, no customer data modification. Your agent watches and reports; it does not touch the money.
Before You Start
Three things need to be in place:
-
OpenClaw installed and running on your machine or a VPS. If you have not done this yet, follow our OpenClaw setup guide. For 24/7 uptime, consider running OpenClaw on Hostinger.
-
A Stripe account with at least test mode enabled. The integration works on both test and live mode. We recommend building and testing in test mode first, then switching to your live restricted key.
-
A text editor for creating your skill file. VS Code, Cursor, or any Markdown editor works.
Step 1: Get Your Stripe API Keys
Stripe provides two types of keys: publishable keys (client-side, safe to expose) and secret keys (server-side, never expose). For OpenClaw, you need a secret key — but not the default one. You should create a restricted key with only the permissions your monitoring agent needs.
Create a Restricted Key
Restricted keys follow the principle of least privilege. Your monitoring agent needs to read payment data, not create charges or modify customer records.
- Log into the Stripe Dashboard
- Navigate to Developers > API Keys
- Click Create restricted key
- Name it
openclaw-monitoringso you can identify it later - Set these permissions:
| Resource | Permission | Why |
|---|---|---|
| Charges | Read | View payment status and failure reasons |
| Customers | Read | Identify who failed payments belong to |
| Disputes | Read | Get notified about chargebacks |
| Invoices | Read | Track invoice payment status |
| Subscriptions | Read | Monitor cancellations and status changes |
| Balance | Read | Pull revenue and payout summaries |
| Events | Read | Access webhook event data via API |
Leave everything else set to None. If your agent cannot write to customers, charges, or subscriptions, it cannot accidentally modify anything even if a prompt injection attempt occurs.
- Click Create key and copy the key immediately. It starts with
rk_live_(orrk_test_in test mode).
Store the Key Safely
Never paste the key directly into your skill file. Store it in a .env file outside your OpenClaw workspace:
# ~/.env or ~/openclaw/.env
STRIPE_SECRET_KEY=rk_live_xxxxxxxxxxxxxxxxxxxxxxxx
OpenClaw reads environment variables at runtime. This keeps the secret out of any file your agent might log or include in context.
Step 2: Write the OpenClaw Stripe Monitoring Skill
OpenClaw skills are Markdown files that teach your agent how to call external APIs. The skill file lives in your workspace’s skills/ directory and contains authentication details, API call templates, and rules.
Create the Skill Directory
mkdir -p ~/.openclaw/workspace/skills/stripe-monitor
Write the SKILL.md File
Create ~/.openclaw/workspace/skills/stripe-monitor/SKILL.md with this content:
---
name: stripe-monitor
description: Monitor Stripe payments, subscriptions, disputes, and revenue. Read-only access to payment data for alerts and reporting.
tools:
- shell
---
# Stripe Payment Monitor
## Authentication
Use the environment variable `STRIPE_SECRET_KEY` for all API requests.
Base URL: `https://api.stripe.com/v1`
All requests use Bearer token authentication:
Authorization: Bearer $STRIPE_SECRET_KEY
## Available Operations
### Check Recent Failed Charges
Retrieve charges that failed in the last 24 hours:
curl -s -G "https://api.stripe.com/v1/charges" \
-H "Authorization: Bearer $STRIPE_SECRET_KEY" \
-d "limit=100" \
-d "created[gte]=$(date -d '24 hours ago' +%s)" \
| jq '[.data[] | select(.status == "failed")] | length as $count | {failed_count: $count, charges: [.[] | {id: .id, amount: (.amount / 100), currency: .currency, failure_message: .failure_message, customer: .customer, created: (.created | todate)}]}'
### List Active Disputes
Fetch all open disputes requiring attention:
curl -s -G "https://api.stripe.com/v1/disputes" \
-H "Authorization: Bearer $STRIPE_SECRET_KEY" \
-d "limit=50" \
| jq '.data[] | select(.status == "needs_response" or .status == "warning_needs_response") | {id: .id, amount: (.amount / 100), currency: .currency, reason: .reason, due_by: (.evidence_details.due_by | todate), charge: .charge}'
### Get Revenue Summary
Pull balance data for revenue overview:
curl -s "https://api.stripe.com/v1/balance" \
-H "Authorization: Bearer $STRIPE_SECRET_KEY" \
| jq '{available: [.available[] | {amount: (.amount / 100), currency: .currency}], pending: [.pending[] | {amount: (.amount / 100), currency: .currency}]}'
### Check Recent Subscription Cancellations
List subscriptions that were canceled in the last 7 days:
curl -s -G "https://api.stripe.com/v1/subscriptions" \
-H "Authorization: Bearer $STRIPE_SECRET_KEY" \
-d "status=canceled" \
-d "limit=50" \
-d "created[gte]=$(date -d '7 days ago' +%s)" \
| jq '.data[] | {id: .id, customer: .customer, cancel_reason: .cancellation_details.reason, canceled_at: (.canceled_at | todate), plan: .items.data[0].price.id}'
### List Failed Invoices
Retrieve invoices that failed to collect payment:
curl -s -G "https://api.stripe.com/v1/invoices" \
-H "Authorization: Bearer $STRIPE_SECRET_KEY" \
-d "status=uncollectible" \
-d "limit=25" \
| jq '.data[] | {id: .id, customer_email: .customer_email, amount_due: (.amount_due / 100), currency: .currency, attempt_count: .attempt_count, next_payment_attempt: .next_payment_attempt}'
## Rules
- This is a READ-ONLY monitoring skill. Never attempt to create, update, or delete any Stripe resources.
- When reporting failed charges, always include the failure reason and customer identifier.
- For disputes, highlight the response deadline. If a dispute is due within 48 hours, flag it as URGENT.
- Convert all amounts from cents to dollars (divide by 100) before presenting to the user.
- Format currency amounts with two decimal places and the currency code.
- Never log or display the full API key in responses or memory files.
- If you receive a 429 rate limit response, wait 10 seconds and retry once.
Why This Skill Is Read-Only
The key principle here: separate your monitoring agent from your payment processing. When a single agent has both read and write access, one misunderstood instruction can refund the wrong charge or cancel an active subscription. A read-only skill eliminates that entire risk category.
If you later want your agent to handle refunds or subscription changes, create a second skill (stripe-actions) with write permissions and stricter confirmation rules. Keep the monitoring skill untouched.
Step 3: Test the Connection
Restart OpenClaw so it picks up the new skill:
openclaw gateway restart
Open your chat interface (Telegram, Slack, or WhatsApp) and try these queries:
Balance check:
“What is my current Stripe balance?”
The agent should return your available and pending balance across currencies.
Failed payments:
“Were there any failed charges in the last 24 hours?”
If you are testing with test mode keys and have no failures, the agent should report zero failures. To generate test data, create a charge with Stripe’s decline test card (4000000000000002) in the dashboard.
Dispute check:
“Do I have any open Stripe disputes?”
The agent should list disputes requiring a response, or confirm none are open.
If any test fails, check these common issues:
| Symptom | Likely Cause | Fix |
|---|---|---|
| 401 Unauthorized | Key is wrong or expired | Check the key in .env matches your Stripe dashboard |
| 403 Forbidden | Restricted key missing a scope | Add the required read permission to your restricted key |
| Empty results | No matching data in account | Use Stripe test mode to generate sample data |
| Timeout | Network issue or rate limit | Wait 10 seconds and retry |
Step 4: Set Up Webhooks for Real-Time Alerts
The skill file covers on-demand queries — you ask, the agent answers. Webhooks flip this around: Stripe pushes events to your agent the moment something happens.
How Webhook-to-Agent Routing Works
Stripe sends HTTP POST requests to a URL you specify whenever events occur. For OpenClaw, you need a lightweight endpoint that receives the webhook, validates the signature, and forwards the event to your agent.
If your OpenClaw instance runs on a VPS with a public IP (like Hostinger), you can set up a simple webhook receiver:
# Install webhook listener (Node.js example)
mkdir -p ~/.openclaw/workspace/webhooks
Create ~/.openclaw/workspace/webhooks/stripe-listener.js:
const http = require('http');
const crypto = require('crypto');
const { execSync } = require('child_process');
const WEBHOOK_SECRET = process.env.STRIPE_WEBHOOK_SECRET;
const PORT = 4242;
const server = http.createServer((req, res) => {
if (req.method !== 'POST' || req.url !== '/stripe-webhook') {
res.writeHead(404);
return res.end();
}
let body = '';
req.on('data', chunk => { body += chunk; });
req.on('end', () => {
// Verify webhook signature
const sig = req.headers['stripe-signature'];
const timestamp = sig.split(',').find(s => s.startsWith('t=')).split('=')[1];
const payload = `${timestamp}.${body}`;
const expected = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(payload)
.digest('hex');
const signatures = sig.split(',')
.filter(s => s.startsWith('v1='))
.map(s => s.split('=')[1]);
if (!signatures.includes(expected)) {
res.writeHead(400);
return res.end('Invalid signature');
}
const event = JSON.parse(body);
handleEvent(event);
res.writeHead(200);
res.end('ok');
});
});
function handleEvent(event) {
const alerts = {
'invoice.payment_failed': `Payment failed: ${event.data.object.customer_email}, $${(event.data.object.amount_due / 100).toFixed(2)}`,
'charge.dispute.created': `New dispute: $${(event.data.object.amount / 100).toFixed(2)}, reason: ${event.data.object.reason}`,
'customer.subscription.deleted': `Subscription canceled: customer ${event.data.object.customer}`,
'charge.refunded': `Refund processed: $${(event.data.object.amount_refunded / 100).toFixed(2)}`
};
const message = alerts[event.type];
if (message) {
// Forward to OpenClaw via CLI
execSync(`openclaw send "${message}"`);
}
}
server.listen(PORT, () => {
console.log(`Stripe webhook listener on port ${PORT}`);
});
Register the Webhook in Stripe
- Go to Developers > Webhooks in your Stripe Dashboard
- Click Add endpoint
- Enter your endpoint URL:
https://your-vps-ip:4242/stripe-webhook - Select these events:
invoice.payment_failedcharge.dispute.createdcustomer.subscription.deletedcharge.refundedcharge.failed
- Copy the Signing secret (starts with
whsec_) and add it to your.env:
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxxxx
- Start the listener:
STRIPE_WEBHOOK_SECRET=$STRIPE_WEBHOOK_SECRET node ~/.openclaw/workspace/webhooks/stripe-listener.js &
Now when a payment fails or a dispute is created, Stripe pushes the event to your listener, which forwards it to your OpenClaw agent, which sends you a message in your chat app of choice.
Step 5: Schedule Recurring Reports
Real-time alerts catch urgent problems. Scheduled reports give you the bigger picture. Use OpenClaw’s heartbeat or cron jobs to run periodic Stripe checks.
Add these to your heartbeat.md or cron configuration:
Daily Revenue Summary (runs at 9:00 AM)
## Stripe Daily Revenue Report
Pull my Stripe balance and list any failed charges from the past 24 hours.
Include the total number of successful charges and their combined value.
If there are any open disputes with a response deadline within 48 hours,
flag them as URGENT at the top of the report.
Send the summary to me via Telegram.
Weekly Churn Report (runs Monday at 8:00 AM)
## Stripe Weekly Churn Report
List all subscriptions that were canceled in the past 7 days.
Group them by cancellation reason if available.
Include the total MRR lost from these cancellations.
Compare this week's cancellation count to the previous week if possible.
Send the report to the SFAI Finance channel on Slack.
This layered approach — real-time alerts for urgent events, daily summaries for operational awareness, weekly reports for trend analysis — is what separates a monitoring setup from a dashboard you forget to check.
Security Considerations
Your Stripe restricted key can read sensitive payment data. Treat it accordingly.
Restricted key scoping. The permission table in Step 1 is intentionally read-only. If you need write access later, create a separate key for a separate skill. Never expand your monitoring key’s permissions.
Token storage. Keep the key in a .env file, not in agents.md, soul.md, or any workspace file. OpenClaw workspace files end up in agent context, and you do not want API keys in a prompt that gets sent to an LLM provider.
Webhook signature verification. The listener script validates Stripe’s webhook signature before processing any event. Without this check, anyone who discovers your webhook URL could send fake events to your agent.
Audit logging. Stripe logs all API requests made with your restricted key. Check Developers > Logs periodically to verify your agent is making the calls you expect and nothing else.
For a deeper dive on securing your OpenClaw setup, see Step 9 in our OpenClaw setup guide.
Frequently Asked Questions
Do I need a paid Stripe plan to use this integration?
No. Stripe’s API is available on the free tier with no monthly fee. You pay Stripe’s standard transaction fees (2.9% + 30 cents per charge in the US), but API access itself costs nothing. The monitoring skill uses read-only endpoints that are available to every Stripe account.
Can OpenClaw alert me the moment a payment fails?
Yes, through webhooks. When you register a webhook endpoint with Stripe and run the listener script from Step 4, failed payments trigger an invoice.payment_failed event that gets forwarded to your agent within seconds. The agent then sends you a message in Telegram, Slack, or whichever channel you use.
What is the difference between using Stripe MCP and a custom skill?
Stripe MCP (via Composio or the official MCP server) gives you pre-built tools with managed authentication. A custom skill gives you full control over which API endpoints your agent calls and how it formats responses. For payment monitoring specifically, we recommend the custom skill approach because you can tailor the API calls to monitoring use cases and avoid loading 30+ payment processing tools your agent does not need.
Is it safe to give my AI agent access to Stripe?
With restricted keys, yes. The key we create in this guide has read-only permissions across charges, customers, disputes, invoices, subscriptions, and balance. Your agent cannot create charges, issue refunds, or modify customer data. The risk is limited to data exposure, which you mitigate by storing the key in .env and never including it in agent context files.
Can I monitor multiple Stripe accounts from one OpenClaw agent?
Yes. Create a separate restricted key for each Stripe account and store them with distinct variable names (STRIPE_KEY_ACCOUNT_A, STRIPE_KEY_ACCOUNT_B). Write a separate skill file or section for each account, referencing the correct environment variable. Your agent can then query each account independently.
How do I get OpenClaw to send me a daily MRR number?
Add a heartbeat instruction that runs daily (see Step 5). The agent pulls your balance data, lists recent successful charges, and calculates the total. For accurate MRR, your heartbeat instruction should specifically ask the agent to sum active subscription values rather than relying on balance snapshots, since the balance includes one-time charges and refunds.
What Stripe events should I monitor for churn?
The three events that signal churn are customer.subscription.deleted (voluntary cancellation), invoice.payment_failed (involuntary churn from failed payments), and customer.subscription.paused (temporary pause). Register all three in your webhook endpoint. The failed payment event is the most actionable because you can trigger a personal outreach before the subscription lapses.
Key Takeaways
- Connect Stripe to OpenClaw by creating a read-only restricted API key and writing a monitoring-focused SKILL.md file
- Use restricted key scoping with only the read permissions you need — charges, customers, disputes, invoices, subscriptions, and balance
- Set up webhooks for real-time alerts on payment failures, disputes, and cancellations
- Add heartbeat or cron instructions for scheduled revenue summaries and churn reports
- Keep monitoring and payment processing in separate skills with separate API keys for safety
- The full integration works on Stripe’s free tier with no paid connectors or middleware required
SFAI Labs