Agent skill

Stripe

by ericrisco in ericrisco/rsc-harness

A skill your agent uses when wiring an app to Stripe for payments, subscriptions, Checkout, webhooks or the billing portal — adding a paywall or paid plan, charging recurring fees, and debugging why…

MITAuto-check passedBackend & APIs

Install Stripe

skills CLI
$ npx skills add ericrisco/rsc-harness --skill stripe -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install ericrisco/rsc-harness stripe --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/stripe .claude/skills/stripe && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
stripe
GitHub stars
167
Token cost
~2.9k tokens
SKILL.md length
881 words
Files
6 (incl. scripts, references)
Skills in repo
227
Repo updated
First seen
Licence
MIT

At a glance

A skill your agent uses when wiring an app to Stripe for payments, subscriptions, Checkout, webhooks or the billing portal — adding a paywall or paid plan, charging recurring fees, and debugging why…

  • Works in 3 steps: Verify against the RAW body.… → Return 2xx before slow work. Verify,… → Be idempotent. Events are unordered and…
  • Wiring an app to Stripe for payments
  • SKILL.md covers When to use / When NOT to use, Pick the surface, Mental model and Construct the client (pin the…, plus 9 more sections
  • Runs Shell scripts from its folder; calls stripe; needs STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET

What it does

Stripe is an agent skill from ericrisco/rsc-harness. Use when wiring an app to Stripe for payments, subscriptions, Checkout, webhooks or the billing portal — adding a paywall or paid plan, charging recurring fees, and debugging why a completion event never fires, why signature verification fails, or why a webhook fires twice and duplicates the order. NOT a generic non-Stripe inbound event receiver (that is webhooks), NOT the invoice document's legal form (that is invoicing), NOT deciding what to charge (that is pricing).

Its SKILL.md is about 2.9k tokens, which your agent loads only when the skill is triggered. The skill folder holds 8 other files, including scripts and reference files (for example `evals/README.md`, `evals/cases.yaml` and `references/going-live.md`).

It sits in Backend & APIs, covering Webhooks. It works with Stripe. The repository describes itself as: Your agent invents things because it has no memory, and can't touch your database because it has no arms. rsc is the meta-harness that gives it both, plus the trade to know the… The licence is MIT.

When your agent uses it

  • Wiring an app to Stripe for payments
  • The billing portal — adding a paywall
  • Charging recurring fees
  • Debugging why a completion event never fires

Example prompts

  • “/stripe”

Requirements

  • Node.js
  • A Bash shell
  • A credential in STRIPE_SECRET_KEY
  • A credential in STRIPE_WEBHOOK_SECRET

Workflow steps

3 steps, taken from the first numbered list in SKILL.md.

  1. Verify against the RAW body. constructEvent recomputes the signature
  2. Return 2xx before slow work. Verify, record the event, return 200
  3. Be idempotent. Events are unordered and may arrive more than once.

What it can do on your machine

Read from SKILL.md and the folder at commit e3d5b33. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships 1 file in scripts/ (Shell), which the agent can run.

    Shell commands in SKILL.md call:

    • stripe

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names these keys or tokens, usually read from environment variables:

    • STRIPE_SECRET_KEY
    • STRIPE_WEBHOOK_SECRET

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Stripe loads about 2.9k tokens when it runs, and up to ~4.5k if it reads all its reference files. Until then it costs about 122 tokens; SKILL.md has 881 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~122
When it runs · the whole SKILL.md, loaded when a task matches
~2.9k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~4.5k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.

SKILL.md

The full file from ericrisco/rsc-harness at commit e3d5b33, republished under its MIT licence (© ericrisco). 881 words, ~2,935 tokens.

Download SKILL.mdSave it as .claude/skills/stripe/SKILL.md (or your agent's skills folder). This skill also uses 5 other files; get the full folder from GitHub.
name
stripe
description
Use when wiring an app to Stripe for payments, subscriptions, Checkout, webhooks or the billing portal — adding a paywall or paid plan, charging recurring fees, and debugging why a completion event never fires, why signature verification fails, or why a webhook fires twice and duplicates the order. NOT a generic non-Stripe inbound event receiver (that is `webhooks`), NOT the invoice document's legal form (that is `invoicing`), NOT deciding what to charge (that is `pricing`).
tags
stripe, payments, subscriptions, checkout, webhooks, billing, saas
recommends
webhooks, invoicing, pricing, secure-coding, nodejs
origin
risco

Stripe — Checkout, subscriptions, and webhooks that survive production

Wire an app to Stripe for one-time payments and subscriptions: a Checkout Session to take money, a signature-verified webhook to learn the outcome, and the billing portal so customers manage themselves. Targets stripe-node v22.x (API version 2026-05-27.dahlia).

The one rule everything else hangs off:

  • Stripe is the source of truth; your DB is a cache kept current by verified webhooks. A subscription's real state lives in Stripe. You mirror it locally only so you can render a paywall without a round-trip. The webhook is what keeps the mirror honest — never the client redirect, never polling.

When to use / When NOT to use

Use when: adding Checkout or a paywall; taking a one-time or recurring charge; receiving Stripe webhooks; letting users cancel/upgrade via the portal; debugging No signatures found matching, double-fired events, or a checkout.session.completed that never arrives.

Do NOT use for:

  • A generic, non-Stripe inbound webhook receiver (arbitrary HMAC, a retry/queue consumer for any provider) → webhooks. This skill only covers Stripe's Stripe-Signature scheme and event model.
  • The invoice document's legal form — what must appear on it, dunning copy, payment-status as a business process → invoicing.
  • Cash-flow forecasting, bank reconciliation, month-close → finance-ops.
  • What to charge / plan tiers / packaging → pricing. This skill implements a price; it does not decide it.
  • A typed client for some other REST API → api-connector-builder.

Pick the surface

You needUseWhy
A link to sell one product, zero codePayment LinkNo backend; Stripe hosts everything. Outgrow it fast.
Hosted checkout, full control of sessionCheckout SessionThe default. Stripe hosts the page, handles SCA/3DS, PCI scope is minimal.
Your own embedded payment formPayment Element + Checkout SessionCustom UI, but you render the form. Use the Element with a Checkout Session, not raw PaymentIntents, unless you have a reason.

Default to Checkout Session unless a requirement forces otherwise.

Mental model

text
Customer ──> Price (you defined it in Stripe) ──> Checkout Session
   │                                                    │
   │                                          customer pays (hosted)
   ▼                                                    ▼
your DB  <── webhook (verified) ── Event <── Subscription / Invoice
(a cache)                                    (the real state, in Stripe)

Env vars used throughout — read from the environment, never hard-code:

  • STRIPE_SECRET_KEY — sk_test_… in dev, sk_live_… in prod.
  • STRIPE_WEBHOOK_SECRET — whsec_…, one per endpoint; differs in test vs live.

Construct the client (pin the API version)

ts
import Stripe from "stripe";

// Pin apiVersion explicitly so a dashboard-level version bump can never change
// your API behavior under you. Match the version your SDK release ships with.
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: "2026-05-27.dahlia",
});

Create a Checkout Session

ts
// Subscription mode — recurring price.
const session = await stripe.checkout.sessions.create({
  mode: "subscription",
  line_items: [{ price: "price_123", quantity: 1 }], // a recurring Price ID
  success_url: `${BASE}/success?session_id={CHECKOUT_SESSION_ID}`,
  cancel_url: `${BASE}/pricing`,
  // Tie the session to YOUR user so the webhook can find the right row.
  client_reference_id: userId,
  // 14-day trial; omit for immediate billing.
  subscription_data: { trial_period_days: 14 },
});
// Redirect the browser to session.url.
ts
// Payment mode — one-time charge (e.g. a digital download).
const session = await stripe.checkout.sessions.create({
  mode: "payment",
  line_items: [{ price: "price_onetime", quantity: 1 }],
  success_url: `${BASE}/success?session_id={CHECKOUT_SESSION_ID}`,
  cancel_url: `${BASE}/`,
  client_reference_id: userId,
});

success_url is a UX redirect, not proof of payment. The customer can close the tab before it loads, or hit the URL directly. Grant access from the webhook, not the redirect.

The webhook handler (load-bearing)

This is where integrations break. Three non-negotiables:

  1. Verify against the RAW body. constructEvent recomputes the signature over the exact bytes Stripe sent. Any middleware that parses/re-serializes the body (e.g. express.json() on this route) changes those bytes and you get No signatures found matching the expected signature.
  2. Return 2xx before slow work. Verify, record the event, return 200 immediately. Stripe treats a timeout as failure and retries — for up to 3 days in live mode — so slow handlers cause duplicate delivery.
  3. Be idempotent. Events are unordered and may arrive more than once. Dedupe on event.id, persisting the idempotency record in the same transaction as the business write. Default replay tolerance is 5 minutes.
ts
// Express. The route gets the RAW body; do NOT mount express.json() here.
app.post("/webhook", express.raw({ type: "application/json" }), async (req, res) => {
  let event: Stripe.Event;
  try {
    event = stripe.webhooks.constructEvent(
      req.body,                          // raw Buffer, untouched
      req.headers["stripe-signature"]!,  // header name is lowercase
      process.env.STRIPE_WEBHOOK_SECRET!,
    );
  } catch (err) {
    return res.status(400).send(`Webhook Error: ${(err as Error).message}`);
  }

  // Dedupe + record in one transaction; skip if we have seen this event.id.
  const fresh = await recordEventOnce(event.id, event.type);
  if (!fresh) return res.status(200).send(); // already processed; ack and stop

  // Return 2xx FAST. Hand heavy work to a queue/background job if it is slow.
  switch (event.type) {
    case "checkout.session.completed": {
      const s = event.data.object as Stripe.Checkout.Session;
      await grantAccess(s.client_reference_id!, s.customer as string);
      break;
    }
    case "customer.subscription.updated":
    case "customer.subscription.deleted": {
      const sub = event.data.object as Stripe.Subscription;
      await syncSubscription(sub.customer as string, sub.status); // mirror state
      break;
    }
    case "invoice.payment_failed":
      // dunning lives here; see references/webhook-events.md
      break;
  }
  res.status(200).send();
});

See references/webhook-events.md for the full event catalog per flow (subscription lifecycle, one-time payment, dunning) and what each event should do to your DB.

Framework gotchas (raw body)
ts
// Next.js App Router — read the raw text yourself; do not use req.json().
// app/api/webhook/route.ts
export async function POST(req: Request) {
  const body = await req.text();                       // raw string
  const sig = req.headers.get("stripe-signature")!;
  const event = stripe.webhooks.constructEvent(body, sig, secret);
  // ...handle, then:
  return new Response(null, { status: 200 });
}
ts
// Edge / Cloudflare Workers — synchronous crypto is unavailable. Use the async
// API with the Web Crypto provider.
const event = await stripe.webhooks.constructEventAsync(
  body, sig, secret, undefined, Stripe.createSubtleCryptoProvider(),
);
Show full SKILL.md (355 more words)Show less

Subscribe to only the events you need

For a subscription paywall, listen to exactly these — listening to "all events" is discouraged and buries you in noise:

checkout.session.completed, customer.subscription.created, customer.subscription.updated, customer.subscription.deleted, invoice.paid, invoice.payment_failed.

Billing portal (self-service)

Do not build cancel/upgrade/update-card UI. Stripe hosts it.

ts
const portal = await stripe.billingPortal.sessions.create({
  customer: stripeCustomerId,             // the Customer you stored
  return_url: `${BASE}/account`,
});
// Redirect to portal.url — it is short-lived; mint it on demand, never cache it.

Idempotency on create calls

A retried POST (network blip, double-click) can create two subscriptions. Pass an idempotency key derived from the operation, not a random one:

ts
await stripe.checkout.sessions.create(params, {
  idempotencyKey: `checkout:${userId}:${planId}`,
});

Local testing — Stripe CLI, never hand-crafted JSON

bash
stripe login
stripe listen --forward-to localhost:3000/api/webhook   # prints a whsec_… secret
stripe trigger checkout.session.completed                # fire a real test event

Put the printed whsec_… in STRIPE_WEBHOOK_SECRET for local runs. Hand-built JSON will never pass signature verification — that is the point.

Going live

Compact checklist; depth in references/going-live.md:

  • apiVersion pinned explicitly in the client.
  • Swap sk_test_/whsec_ (test) for live values via env, not code.
  • Create the live webhook endpoint; copy its own signing secret.
  • Restrict the event subscription to the allowlist above.
  • Use restricted API keys for the server, not the unrestricted secret.
  • Idempotency keys on all create calls.
  • Confirm SCA/3DS is handled (Checkout does this for you).

Anti-patterns

BadGoodWhy
express.json() on the webhook routeexpress.raw() / req.text()Re-serialized body breaks the signature → No signatures found matching.
No constructEvent — trust the payloadAlways verify the signatureAnyone can POST fake events to an unverified endpoint.
Grant access on the success_url redirectGrant on checkout.session.completedThe redirect is UX, not proof; it can be skipped or forged.
DB writes, then return 200Return 200 fast, queue slow workTimeouts make Stripe retry → duplicate delivery.
Process every deliveryDedupe on event.id in the write txnEvents are unordered and at-least-once.
Hard-coded sk_live_… in sourceprocess.env.STRIPE_SECRET_KEYLeaked keys = drained account; never commit them.
No apiVersionPin it explicitlyA dashboard version bump silently changes your API behavior.
Poll the API for subscription stateReact to webhooksPolling is slow, rate-limited, and races real events.
Listen to all event typesSubscribe to the allowlistNoise, wasted handling, accidental side effects.
Cache the portal/session URLMint per requestThese URLs are short-lived and single-use.

See also

  • webhooks — generic, non-Stripe inbound event receivers.
  • invoicing — the invoice document and its legal form.
  • pricing — deciding tiers and amounts before you wire them.
  • secure-coding — secret handling, key restriction.

© ericrisco, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 5 other files (scripts, references) in skills/stripe of ericrisco/rsc-harness.

  • SKILL.md
  • evals/README.md
  • evals/cases.yaml
  • references/going-live.md
  • references/webhook-events.md
  • scripts/verify.sh

Open the folder on GitHubat commit e3d5b33

Compare with similar skills

Stripe next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Stripe compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Stripe this skillericrisco/rsc-harness167—~2.9kAutomated safety check: PassMIT
Stripe Appsfossasia/eventyay1.7k2 repos~3.6kAutomated safety check: PassApache-2.0
Stripe Best Practiceskanchengw/cnllm1753 repos~925Automated safety check: PassApache-2.0
Cashier Stripe Developmentluadotsh/lua3431 repos~1.2kAutomated safety check: PassMIT
Stripe Best Practicesfossasia/eventyay1.7k1 repos~1.7kAutomated safety check: PassApache-2.0
Stripe Integrationwshobson/agents40k10 repos~1kAutomated safety check: PassMIT

Similar skills

  • Stripe Apps

    fossasia/eventyay

    A skill your agent uses when building, modifying, or reviewing a Stripe App — or when the user describes something that implies one (e.g.

    1.7k GitHub starsUsed in 2 repos~3.6k tokens
    Backend & APIsAuto-check passed
  • Stripe Best Practices

    kanchengw/cnllm

    Guides Stripe integration decisions — API selection (Checkout Sessions vs PaymentIntents), Connect platform setup (Accounts v2, controller properties), billing/subscriptions, Treasury financial…

    175 GitHub starsUsed in 3 repos~925 tokens
    Backend & APIsAuto-check passed
  • Handles Laravel Cashier Stripe integration including subscriptions, webhooks, Stripe Checkout, invoices, charges, refunds, trials, coupons, metered billing, and payment failure handling.

    343 GitHub starsUsed in 1 repo~1.2k tokens
    Backend & APIsAuto-check passed
  • Stripe Best Practices

    fossasia/eventyay

    Guides Stripe integration decisions across development and test environment planning (separate sandboxes vs the shared test mode sandbox), API selection (Checkout Sessions vs PaymentIntents)…

    1.7k GitHub starsUsed in 1 repo~1.7k tokens
    Backend & APIsAuto-check passed
  • Stripe Integration

    wshobson/agents

    Implement Stripe payment processing for robust, PCI-compliant payment flows including checkout, subscriptions, and webhooks.

    40k GitHub starsUsed in 10 repos~1k tokens
    Backend & APIsAuto-check passed
  • Convex HTTP Actions

    waynesutton/builder-skills

    Adds HTTP endpoints in convex/http.ts: webhook receivers with signature checks, REST style routes, CORS, auth headers, streaming responses, and file uploads over HTTP.

    404 GitHub stars~2.6k tokensUpdated 10 days ago
    Backend & APIsAuto-check passed

More from ericrisco/rsc-harness

All 227 skills in this repo
  • Ab Testing

    ericrisco/rsc-harness

    A skill your agent uses when designing or analyzing a controlled experiment — falsifiable hypothesis, sample size from an MDE, reading significance/CI/power, CUPED, or rescuing tests that won't go…

    167 GitHub stars~2.4k tokensUpdated today
    Auto-check passed
  • Accessibility

    ericrisco/rsc-harness

    A skill your agent uses when making a web UI conform to WCAG 2.2 Level AA — axe-core or Lighthouse a11y violations, keyboard operability, focus management, ARIA roles/names/live regions, contrast…

    167 GitHub stars~3.4k tokensUpdated today
    Auto-check passed
  • Ads

    ericrisco/rsc-harness

    A skill your agent uses when running or fixing paid acquisition on Google or Meta — campaign structure (Performance Max, Demand Gen, Search, Advantage+), platform-fit creative, budget/scaling rules…

    167 GitHub stars~2.2k tokensUpdated today
    Auto-check passed
  • Agent Eval

    ericrisco/rsc-harness

    A skill your agent uses when measuring whether an LLM or agent system actually got better and gating merges on it: golden sets, fixing an inflated LLM-as-judge, scoring RAG (faithfulness, contextual…

    167 GitHub stars~3.2k tokensUpdated today
    Auto-check passed
  • AI Media

    ericrisco/rsc-harness

    A skill your agent uses when a creative goal must become a finished media file: pick and order generative-media models per modality — AI voiceover, image-to-video clips, score — then glue them with…

    167 GitHub stars~3.3k tokensUpdated today
    Auto-check passed
  • Analytics

    ericrisco/rsc-harness

    A skill your agent uses when instrumenting product or web analytics — GA4/PostHog SDK wiring, event taxonomy, funnels, double-counted events, consent gating, PII scrubbing.

    167 GitHub stars~2.8k tokensUpdated today
    Auto-check passed

Works with

Categories

Questions about Stripe

What does Stripe do?

A skill your agent uses when wiring an app to Stripe for payments, subscriptions, Checkout, webhooks or the billing portal — adding a paywall or paid plan, charging recurring fees, and debugging why…. Stripe is an agent skill from ericrisco/rsc-harness. Use when wiring an app to Stripe for payments, subscriptions, Checkout, webhooks or the billing portal — adding a paywall or paid plan, charging recurring fees, and debugging why a completion event never fires, why signature verification fails, or why a webhook fires twice and duplicates the order.

When should I use Stripe?

Stripe fits situations like: wiring an app to Stripe for payments; the billing portal — adding a paywall; charging recurring fees; debugging why a completion event never fires.

How do I install Stripe in Claude Code?

Run `npx skills add ericrisco/rsc-harness --skill stripe -a claude-code`. Or copy the skill folder (skills/stripe in ericrisco/rsc-harness) into .claude/skills/stripe in your project. Claude Code loads it when a task matches its description.

How do I install Stripe in Codex?

Run `npx skills add ericrisco/rsc-harness --skill stripe -a codex`. Or copy the skill folder (skills/stripe in ericrisco/rsc-harness) into .agents/skills/stripe in your project. Codex loads it when a task matches its description.

Can I use Stripe in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ericrisco/rsc-harness --skill stripe -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/stripe, .gemini/skills/stripe, .github/skills/stripe and .opencode/skills/stripe in your project.

What does Stripe need to run?

Going by SKILL.md and its folder, Stripe needs a shell for the scripts in its folder, the command-line tools its instructions call (stripe) and credentials named STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET. Our summary lists: Node.js; A Bash shell; A credential in STRIPE_SECRET_KEY; A credential in STRIPE_WEBHOOK_SECRET.

Does Stripe access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Stripe safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.

What licence does Stripe use?

Stripe is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Stripe use?

About 2.9k tokens (SKILL.md is roughly 12k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 1.5k tokens, read only when the agent opens those files.

What are the alternatives to Stripe?

Skills that share tags, products or a category with Stripe: Stripe Apps (fossasia/eventyay, 1.7k stars), Stripe Best Practices (kanchengw/cnllm, 175 stars), Cashier Stripe Development (luadotsh/lua, 343 stars) and Stripe Best Practices (fossasia/eventyay, 1.7k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Stripe?

ericrisco (a GitHub user) maintains it in ericrisco/rsc-harness, which has 167 GitHub stars. The repository holds 227 skills in this directory. The repository was last updated on October 7, 2026.

Source: ericrisco/rsc-harness on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.