Skill Stripe Monitor

v1.0.2

Stripe revenue dashboard in your agent — MRR, churn, new subscriptions, failed payments, and alerts. Use when the operator asks about revenue, subscriptions,...

0· 88·0 current·0 all-time
Security Scan
Capability signals
CryptoCan make purchases
These labels describe what authority the skill may exercise. They are separate from suspicious or malicious moderation verdicts.
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Benign
medium confidence
Purpose & Capability
The name/description (Stripe revenue dashboard) matches the instructions: it only performs read-only Stripe API calls and asks only for STRIPE_SECRET_KEY (and an optional webhook secret). One minor mismatch: registry metadata lists no required binaries, but README/SKILL.md call out curl and jq as required utilities.
Instruction Scope
SKILL.md stays within read-only operations (subscriptions, invoices, charges, events) and gives concrete curl/jq examples. It does not instruct reading unrelated files or contacting unexpected third‑party endpoints. However, the README and SKILL-FULL.md suggest storing the API key in ~/.openclaw/openclaw.json and describe automatic alerts ('reacts immediately') and scheduled summaries — these imply persistent/scheduled invocation and a location where secrets may be stored in plaintext. Confirm where secrets will be kept and how alerts/scheduling are implemented before trusting a live secret.
Install Mechanism
Instruction-only skill with no install/download steps (low install risk). It relies on host utilities (curl, jq) but does not install code or fetch remote archives. The lack of an install spec is consistent with the provided shell-based examples.
Credentials
The skill only requires STRIPE_SECRET_KEY (and optionally STRIPE_WEBHOOK_SECRET for webhook verification), which is appropriate for the described functionality. The docs explicitly recommend using a Restricted (read-only) key — follow this. Storing a full secret key in an agent/global config file (example shown) would increase risk and is not necessary if you use a restricted key or test key.
Persistence & Privilege
always:false (no forced global presence). But the skill describes scheduled daily summaries and automated alerts that 'react immediately' — this implies background invocation (scheduler or webhook) which increases the blast radius if a live secret is used. Confirm whether your OpenClaw deployment will run the skill autonomously or only on explicit user invocation.
Assessment
This skill appears to do what it says (read-only Stripe metrics) and requests only the Stripe key it needs, but take precautions before installing: 1) Prefer a Stripe Restricted Key with only the read scopes listed rather than a full secret (sk_live_...) so the skill cannot modify data. 2) Avoid placing the key in global plaintext config if possible; prefer environment variables or a secrets store. 3) Verify how the agent will run scheduled summaries/alerts — if autonomous background polling or webhook handling is enabled, consider using a test key first to confirm behavior. 4) Ensure curl and jq are present on the host as the skill expects them. 5) Note the package source has no homepage and the registry owner is opaque—if you need stronger trust, ask the publisher for a verified homepage or inspect the agent/runtime integration that will execute the curl commands. If any of the above give you pause, install only in a sandbox or use a test/restricted key first.

Like a lobster shell, security has layers — review code before you run it.

Runtime requirements

EnvSTRIPE_SECRET_KEY
latestvk979wss3rn8qma2aphj43bw1vs84g4ex
88downloads
0stars
3versions
Updated 1w ago
v1.0.2
MIT-0

skill-stripe-monitor

Live Stripe revenue metrics in your agent. MRR, new subscriptions, cancellations, failed payments, and top products — on demand or on a schedule.

When to Use

USE this skill when:

  • "What's my MRR?"
  • "Any failed payments today?"
  • "How many new subscribers this month?"
  • "Show me my Stripe status"
  • /stripe mrr, /stripe failures, /stripe subscribers, /stripe status
  • Scheduled daily revenue briefing

DON'T use this skill when:

  • Modifying Stripe data (charges, refunds, plan changes) — this skill is read-only
  • Detailed invoice reconciliation — use Stripe dashboard directly
  • Tax reporting — use Stripe Tax or an accountant

Setup

1. Get your Stripe API key

Go to dashboard.stripe.com/apikeys.

Use a Restricted Key (recommended) with read-only access to:

  • customers — read
  • subscriptions — read
  • invoices — read
  • charges — read
  • products / prices — read

Or use your Secret Key (sk_live_...) for full access — fine for personal use.

2. Store the key

Set the STRIPE_SECRET_KEY environment variable:

export STRIPE_SECRET_KEY="sk_live_..."

Use a Restricted Key scoped to read-only access for safety.

3. Verify connection

Ask your agent: "Check my Stripe connection" or run /stripe status.


Commands

CommandWhat it does
/stripe statusQuick health check — live mode, currency, recent activity
/stripe mrrCurrent MRR and 30-day trend
/stripe subscribersActive subscriber count, new this month, churn this month
/stripe failuresFailed payments in the last 7 days
/stripe topTop 5 products/plans by revenue
/stripe summaryFull daily summary (all of the above)

How to Resolve the API Key

Before making any Stripe API call, read the key from the environment variable:

STRIPE_KEY="${STRIPE_SECRET_KEY:-}"

if [ -z "$STRIPE_KEY" ]; then
  echo "ERROR: STRIPE_SECRET_KEY not set. See Setup section in SKILL.md."
  exit 1
fi

All examples below assume $STRIPE_KEY is set via this resolution step.


API Patterns

All Stripe API calls use HTTP Basic auth — key as username, empty password:

curl -s -u "$STRIPE_KEY:" "https://api.stripe.com/v1/..."

Get MRR

Stripe doesn't expose MRR directly. Calculate it from active subscriptions:

# Fetch active subscriptions (paginate if needed)
curl -s -u "$STRIPE_KEY:" \
  "https://api.stripe.com/v1/subscriptions?status=active&limit=100&expand[]=data.items.data.price" \
  | jq '
    [.data[].items.data[] | 
      .price.unit_amount / 100 * 
      (if .price.recurring.interval == "year" then 1/12 
       elif .price.recurring.interval == "week" then 4.33
       else 1 end)
    ] | add // 0 | . * 100 | round / 100
  '

For more than 100 subscriptions, paginate using starting_after:

# Get all active subscriptions (handles pagination)
ALL_SUBS="[]"
LAST_ID=""

while true; do
  PARAMS="status=active&limit=100&expand[]=data.items.data.price"
  if [ -n "$LAST_ID" ]; then
    PARAMS="${PARAMS}&starting_after=${LAST_ID}"
  fi
  
  RESP=$(curl -s -u "$STRIPE_KEY:" "https://api.stripe.com/v1/subscriptions?${PARAMS}")
  PAGE=$(echo "$RESP" | jq '.data')
  ALL_SUBS=$(echo "$ALL_SUBS $PAGE" | jq -s 'add')
  
  HAS_MORE=$(echo "$RESP" | jq -r '.has_more')
  [ "$HAS_MORE" = "false" ] && break
  LAST_ID=$(echo "$RESP" | jq -r '.data[-1].id')
done

echo "$ALL_SUBS" | jq '
  [.[].items.data[] | 
    .price.unit_amount / 100 *
    (if .price.recurring.interval == "year" then 1/12
     elif .price.recurring.interval == "week" then 4.33
     else 1 end)
  ] | add // 0
'

New Subscriptions This Month

# Start of current month (Unix timestamp)
MONTH_START=$(date -u +%s -d "$(date +%Y-%m-01)" 2>/dev/null || \
              date -u -j -f "%Y-%m-%d" "$(date +%Y-%m-01)" +%s)

curl -s -u "$STRIPE_KEY:" \
  "https://api.stripe.com/v1/subscriptions?status=active&limit=100&created[gte]=${MONTH_START}" \
  | jq '.data | length'

Cancellations This Month

MONTH_START=$(date -u +%s -d "$(date +%Y-%m-01)" 2>/dev/null || \
              date -u -j -f "%Y-%m-%d" "$(date +%Y-%m-01)" +%s)

curl -s -u "$STRIPE_KEY:" \
  "https://api.stripe.com/v1/subscriptions?status=canceled&limit=100&canceled_at[gte]=${MONTH_START}" \
  | jq '.data | length'

Failed Payments (Last 7 Days)

SEVEN_DAYS_AGO=$(( $(date -u +%s) - 604800 ))

curl -s -u "$STRIPE_KEY:" \
  "https://api.stripe.com/v1/charges?limit=100&created[gte]=${SEVEN_DAYS_AGO}" \
  | jq '[.data[] | select(.status == "failed")] | 
    {
      count: length,
      total_failed: ([.[].amount] | add // 0) / 100,
      failures: [.[] | {id, amount: (.amount/100), currency, description, created}]
    }'

Top Products by Revenue (Last 30 Days)

THIRTY_DAYS_AGO=$(( $(date -u +%s) - 2592000 ))

curl -s -u "$STRIPE_KEY:" \
  "https://api.stripe.com/v1/invoices?limit=100&status=paid&created[gte]=${THIRTY_DAYS_AGO}" \
  | jq '
    [.data[].lines.data[] | {product: .description, amount: .amount}]
    | group_by(.product)
    | map({product: .[0].product, revenue: ([.[].amount] | add) / 100})
    | sort_by(-.revenue)
    | .[:5]
  '

Account Status Check

curl -s -u "$STRIPE_KEY:" "https://api.stripe.com/v1/balance" \
  | jq '{
      available: [.available[] | {currency, amount: (.amount/100)}],
      pending: [.pending[] | {currency, amount: (.amount/100)}],
      livemode: .livemode
    }'

Full /stripe summary Response

When the operator asks for a full summary or /stripe summary, assemble and report all of the following:

💳 Stripe Summary — [Date]

MRR: $X,XXX
Active subscribers: XXX
New this month: XX (+X.X%)
Cancellations this month: XX (churn: X.X%)

Failed payments (7d): X ($XXX total)
  ↳ Most recent: [customer/description] — $XX — [time ago]

Top products (30d):
  1. [Product name] — $X,XXX
  2. [Product name] — $X,XXX
  3. [Product name] — $X,XXX

Balance: $X,XXX available / $X,XXX pending
Mode: live ✅  (or test ⚠️)

If any metric fails to fetch, report it as "unavailable" and continue.


Scheduled Daily Summary

To receive a daily Stripe summary via Telegram, set up a cron-style heartbeat task or use OpenClaw's scheduler.

Example HEARTBEAT.md entry:

## Daily Stripe Summary
- Time: 08:00 CET
- Action: Run /stripe summary and send to Telegram

Or ask: "Set up a daily Stripe summary at 8am."


Alerts

Alert the operator when you detect:

EventTriggerMessage
Failed paymentAny charge with status: failed created in the last hour⚠️ Failed payment: $XX from [description]
New subscriptionSubscription created in the last hour🎉 New subscriber! Plan: [name], $XX/mo
CancellationSubscription cancelled in the last hour📉 Cancellation: [customer], was on [plan]

To check for recent events (last 60 minutes):

ONE_HOUR_AGO=$(( $(date -u +%s) - 3600 ))

# Recent events
curl -s -u "$STRIPE_KEY:" \
  "https://api.stripe.com/v1/events?limit=50&created[gte]=${ONE_HOUR_AGO}&types[]=customer.subscription.created&types[]=customer.subscription.deleted&types[]=charge.failed" \
  | jq '.data[] | {type, created, data: .data.object}'

For real-time alerts without polling, configure a Stripe Webhook (optional):

  1. Go to dashboard.stripe.com/webhooks
  2. Add endpoint: your OpenClaw webhook URL
  3. Select events: charge.failed, customer.subscription.created, customer.subscription.deleted
  4. Store the webhook signing secret as STRIPE_WEBHOOK_SECRET (used to verify payloads)

Webhook support requires a publicly reachable OpenClaw instance. Polling (above) works without any webhook setup.


Error Handling

HTTP statusMeaningAction
401Invalid API keyAsk operator to verify STRIPE_SECRET_KEY
403Restricted key missing permissionCheck key permissions in Stripe dashboard
429Rate limitedWait and retry with exponential backoff
5xxStripe outageCheck status.stripe.com, retry later

On 429, use this pattern:

RETRY_AFTER=$(curl -sI -u "$STRIPE_KEY:" "https://api.stripe.com/v1/balance" \
  | grep -i "retry-after" | awk '{print $2}' | tr -d '\r')
sleep "${RETRY_AFTER:-5}"

Notes

  • All amounts from Stripe are in smallest currency unit (cents for USD/EUR). Always divide by 100 before displaying.
  • MRR calculation normalizes annual and weekly plans to monthly. This is an approximation.
  • The Stripe API paginates at 100 items. For businesses with >100 active subscriptions, always paginate (see MRR pattern above).
  • Test mode keys (sk_test_...) work identically — the status check will flag livemode: false so you don't accidentally report test data as real.

Comments

Loading comments...