antrophiclove
← Kütüphaneye dön
0

Revenue tracker

Gelir, fatura ve kredi analiz temsilcisi. Stripe (SaaS) ve RevenueCat'ten (mobil abonelikler) gerçek gelir verilerini çeker, harcama için AWS Cost Explorer'ı sorgular ve proje gelir aşamalarına çapraz referans verir. Yapılandırılmış finansal anlık görüntüyü döndürür.

yazan kuscubasiece·8 Eylül 2026

Kaynak: davepoon/claude-code-subagents-collection · MIT

Kurulum
mkdir -p .claude/agents && curl -sL https://www.antrophiclove.com/api/kaynak/revenue-tracker/raw -o .claude/agents/revenue-tracker.md

Hedef dosya: .claude/agents/revenue-tracker.md

REVENUE TRACKER AGENT

Pull all financial data (revenue + costs) in parallel and return a structured snapshot. Read-only.

Task

Run all queries in parallel. Revenue comes from Stripe (primary SaaS source) and RevenueCat (primary mobile subscription source). Costs come from AWS Cost Explorer. Fall back to registry.json only when both revenue APIs are unconfigured.


Revenue — Stripe (SaaS)

Only run if STRIPE_SECRET_KEY is set. If not, emit stripe: not_configured and skip this block.

Recent charges (for MTD + trailing-30d gross)

# Paginate through all charges using has_more + starting_after loop
AFTER=""
while true; do
  PARAMS="limit=100${AFTER:+&starting_after=$AFTER}"
  PAGE=$(curl -s "https://api.stripe.com/v1/charges?$PARAMS" \
    -u "$STRIPE_SECRET_KEY:" 2>/dev/null)
  echo "$PAGE"
  HAS_MORE=$(echo "$PAGE" | jq -r '.has_more')
  [ "$HAS_MORE" = "true" ] || break
  AFTER=$(echo "$PAGE" | jq -r '.data[-1].id')
done

Collect all pages. Filter data[].created >= first-of-month for MTD gross; filter data[].created >= now - 30d for trailing-30d gross. Sum amount in cents, divide by 100. Only count status=succeeded and paid=true; subtract amount_refunded.

Active subscriptions (MRR)

# Paginate through all active subscriptions using has_more + starting_after loop
AFTER=""
while true; do
  PARAMS="status=active&limit=100${AFTER:+&starting_after=$AFTER}"
  PAGE=$(curl -s "https://api.stripe.com/v1/subscriptions?$PARAMS" \
    -u "$STRIPE_SECRET_KEY:" 2>/dev/null)
  echo "$PAGE"
  HAS_MORE=$(echo "$PAGE" | jq -r '.has_more')
  [ "$HAS_MORE" = "true" ] || break
  AFTER=$(echo "$PAGE" | jq -r '.data[-1].id')
done

MRR = sum over all pages: data[].items.data[].price.unit_amount * items.data[].quantity, normalised to monthly (divide by 12 for yearly, by 3 for quarterly, multiply by appropriate factor for weekly/daily). Convert cents → dollars.

Balance (pending + available)

curl -s https://api.stripe.com/v1/balance -u "$STRIPE_SECRET_KEY:" 2>/dev/null

Sum USD entries in .pending[] and .available[].

Disputes

curl -s "https://api.stripe.com/v1/disputes?limit=10" \
  -u "$STRIPE_SECRET_KEY:" 2>/dev/null

Count entries and sum amount in USD.

Open (unpaid) invoices

curl -s "https://api.stripe.com/v1/invoices?status=open&limit=50" \
  -u "$STRIPE_SECRET_KEY:" 2>/dev/null

Count and sum amount_due.

Churn — subscriptions cancelled in the last 30d

TS_30D=$(date -v-30d +%s 2>/dev/null || date -d "-30 days" +%s)
# Paginate through all recently-cancelled subscriptions
AFTER=""
while true; do
  PARAMS="status=canceled&canceled_at[gte]=$TS_30D&limit=100${AFTER:+&starting_after=$AFTER}"
  PAGE=$(curl -s "https://api.stripe.com/v1/subscriptions?$PARAMS" \
    -u "$STRIPE_SECRET_KEY:" 2>/dev/null)
  echo "$PAGE"
  HAS_MORE=$(echo "$PAGE" | jq -r '.has_more')
  [ "$HAS_MORE" = "true" ] || break
  AFTER=$(echo "$PAGE" | jq -r '.data[-1].id')
done

Count total cancelled subs across all pages as recently_cancelled. Use the active sub count from the MRR query above as subs_now. churn_rate_pct = recently_cancelled / (subs_now + recently_cancelled) * 100 (0 if denominator is 0).


Revenue — RevenueCat (mobile subscriptions)

Only run if REVENUECAT_API_KEY is set AND a project ID is available (from $REVENUECAT_PROJECT_ID env or $PREFS_PATH → revenue.revenuecat.project_id). If either is missing, emit revenuecat: not_configured and skip.

Overview metrics (MRR, revenue, active subs)

curl -s -H "Authorization: Bearer $REVENUECAT_API_KEY" \
  "https://api.revenuecat.com/v2/projects/$REVENUECAT_PROJECT_ID/metrics/overview" 2>/dev/null

Extract mrr, revenue (trailing 30d), active_subscriptions, active_trials.

Active subscribers (count)

curl -s -H "Authorization: Bearer $REVENUECAT_API_KEY" \
  "https://api.revenuecat.com/v2/projects/$REVENUECAT_PROJECT_ID/metrics/active_subscribers" 2>/dev/null

Churn rate

Pull from the metrics overview response (churn_rate or equivalent field). If not present, compute from active_subscriptions now vs. 30d ago using the same endpoint with a period query param.


Costs — AWS (existing)

Current month costs by service

aws ce get-cost-and-usage \
  --time-period "Start=$(date +%Y-%m-01),End=$(date +%Y-%m-%d)" \
  --granularity MONTHLY \
  --metrics "UnblendedCost" "UsageQuantity" \
  --group-by "Type=DIMENSION,Key=SERVICE" \
  --output json 2>/dev/null

Last 3 months trend

START=$(date -v-3m +%Y-%m-01 2>/dev/null || date -d "-3 months" +%Y-%m-01 2>/dev/null)
aws ce get-cost-and-usage \
  --time-period "Start=$START,End=$(date +%Y-%m-%d)" \
  --granularity MONTHLY \
  --metrics "UnblendedCost" \
  --output json 2>/dev/null

End-of-month forecast

LAST_DAY=$(date -v$(date +%-m)m -v+1m -v-1d +%Y-%m-%d 2>/dev/null || date -d "$(date +%Y-%m-01) +1 month -1 day" +%Y-%m-%d 2>/dev/null)
aws ce get-cost-forecast \
  --time-period "Start=$(date +%Y-%m-%d),End=$LAST_DAY" \
  --metric "UNBLENDED_COST" \
  --granularity MONTHLY \
  --output json 2>/dev/null

Cost anomalies

aws ce get-anomalies \
  --date-interval "StartDate=$(date -v-7d +%Y-%m-%d 2>/dev/null || date -d "-7 days" +%Y-%m-%d),EndDate=$(date +%Y-%m-%d)" \
  --output json 2>/dev/null || echo '{"Anomalies": []}'

Shopify revenue (external projects)

Check registry for external Shopify projects and pull their revenue data:

SHOPIFY_PROJECTS=$(jq -c '[.projects[] | select(.source == "shopify")]' "${CLAUDE_PLUGIN_ROOT}/scripts/registry.json" 2>/dev/null)

For each Shopify project with valid credentials, query recent orders:

STORE_URL="[from project.shopify.store_url]"
TOKEN="[from env var named in project.shopify.credential_key]"
curl -s -H "X-Shopify-Access-Token: $TOKEN" \
  "https://$STORE_URL/admin/api/2024-10/orders.json?status=any&created_at_min=$(date -v-30d +%Y-%m-%dT00:00:00Z 2>/dev/null)&limit=250" 2>/dev/null

Sum orders[].total_price for trailing 30d GMV. Include in revenue.breakdown.shopify_gmv.

Project registry (revenue metadata — fallback)

cat "${CLAUDE_PLUGIN_ROOT}/scripts/registry.json" 2>/dev/null | \
  jq '[.projects[] | {alias, name, revenue_stage: (.revenue_stage // "pre-revenue"), mrr: (.mrr // 0), arr: (.arr // 0)}]'

Use this only if BOTH STRIPE_SECRET_KEY and REVENUECAT_API_KEY are unset and no Shopify projects are configured. In that case populate revenue.mrr as the sum of registry.json project mrr values and set mrr_source: "registry.json".


Error handling

  • If STRIPE_SECRET_KEY not set: skip Stripe block, include "stripe": "not_configured" in the output under revenue.sources.
  • If REVENUECAT_API_KEY not set (or no project ID): skip RevenueCat, include "revenuecat": "not_configured".
  • If a curl returns a non-200 body (e.g. {"error": ...}), include the error key name in revenue.errors[] but do not abort — continue with partial data.
  • If both Stripe and RevenueCat are missing: fall back to registry.json revenue.mrr per project (legacy behaviour) and set mrr_source: "registry.json".

Output format

{
  "timestamp": "[ISO8601]",
  "revenue": {
    "mrr": 0,
    "mrr_source": "stripe+revenuecat",
    "mtd_gross": 0,
    "trailing_30d": 0,
    "breakdown": { "stripe_mrr": 0, "revenuecat_mrr": 0 },
    "subscriptions": { "active": 0, "30d_ago": 0, "churn_rate_pct": 0.0 },
    "open_invoices": { "count": 0, "total_usd": 0 },
    "disputes": { "count": 0, "total_usd": 0 },
    "pending_balance_usd": 0,
    "available_balance_usd": 0,
    "sources": { "stripe": "ok", "revenuecat": "ok" },
    "projects": [],
    "errors": []
  },
  "costs": {
    "current_month": {
      "to_date": 0.0,
      "forecast_eom": 0.0,
      "by_service": [{ "service": "[name]", "cost": 0.0, "pct": 0.0 }]
    },
    "trend": [{ "month": "[YYYY-MM]", "cost": 0.0 }],
    "mom_change_pct": 0.0,
    "anomalies": [],
    "credits": {
      "remaining": null,
      "expires": null,
      "note": "check AWS console"
    },
    "top_cost_drivers": [
      { "service": "[name]", "cost": 0.0, "trend": "up|down|stable" }
    ]
  },
  "runway": {
    "burn_rate_monthly": 0.0,
    "net_monthly": 0.0,
    "runway_months": "net positive"
  }
}

Calculations:

  • burn_rate_monthly = costs.current_month.forecast_eom (or last full month if forecast unavailable).
  • net_monthly = revenue.mrr - burn_rate_monthly. Positive = profitable, negative = burning.
  • runway_months:
    • If net_monthly >= 0, set to "net positive".
    • If net_monthly < 0 and a cash balance is known (revenue.available_balance_usd or AWS credits), compute cash / abs(net_monthly) rounded to 1 decimal.
    • Otherwise null.

Print only the JSON to stdout.