SP

SparkPay

dev.sparkpay/sparkpay

Stripe billing for indie apps: plans, coupons, subscriptions, customers and revenue reporting.

Yes, your AI can use this right now.Answered a live MCP handshake in 369 ms with no sign-in needed and exposes 25 tools.

Use Stripe with: ChatGPT · Claude · Cursor · Claude Code · VS Code

Is this your server? Claim the listing. Verified adds a vendor-confirmed mark on this page and matching app pages.
Claim with Verified — $49/moWant it in front of people comparing Finance & Payments tools? Feature it — $149/mo

Connect it

Settings → Connectors → Add custom connector
URL: https://sparkpay.dev/api/mcp/mcp

25 tools, pulled live

Pulled straight from the server with tools/list on 2026-10-27.
list_appsread-only

List the registered apps (app_id + name). Use this first to discover valid app_id values, then pass one to the other tools to scope results to a single product.

list_subscriptionsread-only

List subscriptions/registrations, newest first. Optionally filter by app_id, status, or payment_type. Returns metadata (email, status, plan, amounts). Use get_customer for a single user, or revenue_summary for totals.

get_customerread-only

Look up a customer by email. Returns every subscription/registration for that email across apps (or within one app if app_id is given), with full detail: verification, plan, billing period, usage, refunds. Empty when the email is unknown.

list_recent_paymentsread-only

List recent paid transactions (excludes free-tier rows), newest first, ordered by payment date. Optionally scope by app_id. Use to review recent sales activity. Amounts are in the transaction currency (cents).

revenue_summaryread-only

Revenue and subscriber summary in USD cents (normalized from each transaction currency). Returns latest_payments (the MOST RECENT payment summed per customer: a run-rate, NOT lifetime turnover, because amount_paid is overwritten on renewal), refunds, approximate MRR, active/trialing/paid counts, and lifetime_net (the only cumulative total held, accrued per OWNER across all their apps and net of re

revenue_by_appread-only

Per-app rollup in USD cents (latest_payments/refunded/MRR + paid customer count), largest refund-adjusted latest payments first. latest_payments sums the most recent payment per customer, so it is a run-rate and NOT lifetime turnover. No lifetime figure is available per app (accrual is recorded per owner). Use to compare products at a glance; use revenue_summary for one app in depth.

list_referralsread-only

List referral records (who referred whom, reward coupon code, pending/rewarded status), newest first. Optionally scope by app_id and/or status.

list_recent_cancellationsread-only

Recently canceled paid subscriptions (excludes free rows), most recent cancellation first, with what each customer was paying. Use for churn review; list_subscriptions orders by signup date instead.

list_couponsread-only

List discount coupons (code, percent off, expiry, max uses, use count, which paid tiers they apply to). Optionally scope by app_id and/or restrict to currently-active ones (not expired, not maxed out). Read-only: cannot create, edit, or delete coupons.

create_coupon

Create a percentage discount coupon for an app. WRITE, human-gated: a real create requires an elicitation-capable client (e.g. Claude Desktop). The human enters the final code, percent, expiry, visibility, and tier scope in a form; those values OVERRIDE the arguments here, which only pre-fill the form message as a proposal. Clients without elicitation are refused (dry_run still works anywhere). In

bulk_create_coupon

Create the SAME discount code across many apps in one call: the portfolio-promo shortcut (e.g. a summer sale on every owned app). WRITE, human-gated: a real create requires an elicitation-capable client; the human enters the coupon terms ONCE in a form (overriding the arguments here) and that one approval covers the whole batch. Clients without elicitation are refused (dry_run still works anywhere

delete_couponcan modify

Delete one coupon from an app. WRITE, human-gated: a real delete requires an elicitation-capable client; the human sees the exact coupon (code, percent, redemption count) and must click approve. The model cannot confirm on its own, and confirm_used is only consulted for dry_run previews. Clients without elicitation are refused (dry_run still works anywhere). Removes the Stripe coupon object and th

bulk_delete_couponcan modify

Delete the SAME coupon code across many apps in one call: the inverse of bulk_create_coupon, for retiring a portfolio-wide promo. WRITE, human-gated: a real delete requires an elicitation-capable client; the human sees every app the code would be removed from (with per-app redemption counts) and must click approve, and confirm_used is only consulted for dry_run previews. Clients without elicitatio

set_coupon_listed

Show, hide or SCHEDULE an EXISTING coupon on the public pricing pages by setting its `listed` flag and optional `listed_from` start date. WRITE, human-gated: a real write requires an elicitation-capable client and the human sees the code, the discount, which way it is moving and any start date; clients without elicitation are refused (dry_run works anywhere). These are deliberately the ONLY fields

list_coupon_invitesread-only

List who a coupon was offered to and what they did with it: per-address status (invited / redeemed / revoked), where the invite came from, and the timestamps. Also returns the coupon's own `invite_only` flag -- read that FIRST: when it is false the invite rows are recorded but NOT enforced, and anyone holding the code can still redeem it. Read-only. Use list_coupons for the coupon's terms, invite_

invite_to_coupon

Add email addresses to a coupon's invite list and, by default, switch the coupon to invite-only so the list is actually enforced. WRITE, human-gated: a real write requires an elicitation-capable client and the human sees every address plus whether the coupon is about to be closed to everyone else; clients without elicitation are refused (dry_run works anywhere). Addresses are lowercased and de-dup

revoke_coupon_invitecan modify

Withdraw one address's right to spend a coupon: the targeted block. WRITE, human-gated: a real write requires an elicitation-capable client and the human sees the address and its current status; clients without elicitation are refused (dry_run works anywhere). Works on an address that was never invited too, writing a revoked tombstone, so blocking someone does not depend on whether they were on th

plan_app_kitread-only

Step 1 of onboarding a new app onto SparkPay. Recons app_name against existing apps and the rest of the portfolio's plan catalogs, then returns automated findings plus the minimum set of questions that genuinely need a human answer (plan prices, billing model, redirect URLs, trial length, push-webhook opt-in). Pass the answers to create_app_kit next.

create_app_kitcan modify

Step 2 of onboarding a new app onto SparkPay. Applies answers.plan_catalog by minting real Stripe prices (same helper /api/apps/sync-plans uses) and registers/updates the app, then returns a downloadable integration kit (lib/spark-pay client + plans.json + sync script + INTEGRATION.md, modeled on still-applying's golden pattern) plus exact post_steps for env vars and secrets. Refuses to overwrite

list_plansread-only

Download an app's live plan catalog: tiers, names, prices, trial, and the machine-readable `limits` that gate features inside the app. This is the source of truth each app repo's `bun run plans:sync` regenerates lib/spark-pay/plans.json from, so diff against this rather than trusting the committed file. Stripe price/product IDs are omitted unless include_stripe_ids is set.

update_plan_limitscan modify

Change the usage limits on an app's existing tiers (e.g. set ai_generations_daily to 200 on pro). WRITE, human-gated: a real write requires an elicitation-capable client; the human sees the per-tier before -> after diff and must click approve. Clients without elicitation are refused (dry_run still works anywhere). Tier-keyed, so one call can set a new limit key across every tier in a single atomic

update_plan_metacan modify

Set an existing tier's display metadata: its name and the two badge flags the public pricing page styles cards from: is_elite (gold/carbon BEST VALUE card with the rainbow title and app icon) and recommended (MOST POPULAR). A tier called "Elite" is NOT styled as elite unless is_elite is actually true on the stored plan; the page reads the flag, never the tier slug, so a catalog whose top tier lack

update_plan_pricingcan modify

Change what an app's EXISTING tiers charge: the amount, the billing model (one_time vs subscription), or both. WRITE, human-gated at the highest tier: a real write requires an elicitation-capable client, and the human types the tier, billing model and price into a form. Those typed values OVERRIDE the arguments here, which only pre-fill the proposal, so the model cannot move a price on its own. Cl

archive_plancan modify

Remove a tier from an app's plan catalog. WRITE, human-gated: a real write needs an elicitation-capable client and the human must approve; dry_run previews anywhere. Every other plan tool edits tiers that already exist, so a catalog could grow but never shrink, and collapsing a multi-tier page down to a single offer was a dashboard-only job. Stripe products and prices are deliberately left intact,

setup_pricing_pagecan modify

Guided, stage-chained wizard that configures an app's hosted pricing page end to end: plan billing model + price (with clickable recommendations), plan name and badge (elite/recommended), optional free tier, a seasonal coupon (SUMMER26-style code suggested from the current season), favicon-derived theme color + card style, and FAQ content. WRITE, human-gated per stage: each call runs AT MOST ONE e

Alternatives in Finance & Payments

Compare →
Try “Notion”, “Stripe”, “create invoice”, “browser”