stripe-refund-dispute-lifecycle
Use when implementing any handler that revokes credits or mutates a paid-status column in response to Stripe refund or dispute events.
Works with
Agent Skills format with YAML frontmatter. Claude Code reads it as-is.
---
name: "stripe-refund-dispute-lifecycle"
description: "Use when implementing any handler that revokes credits or mutates a paid-status column in response to Stripe refund or dispute events."
license: "MIT"
---
## Quick Reference
| Event | Action | Key rule |
|--|--|--|
| `charge.refunded` | Revoke credits proportional to refund delta | G2 — `previous_attributes.amount_refunded` |
| `charge.dispute.created` | Set user `past_due` + store checkpoint | G1 + G9 |
| `charge.dispute.closed` | `won` / `warning_closed` / `prevented` -> restore; `lost` -> no-op (charge.refunded handles); else -> no-op | G5 + G7 |
| Refund source priority | When to use |
|--|--|
| `event.data.previous_attributes.amount_refunded` (G2) | Primary — always prefer |
| `charge.refunds.data` (sorted by created desc) | Fallback when `previous_attributes` absent |
| `stripe.refunds.list({charge, limit:1})` | Last resort when embedded missing |
| `charge.amount_refunded` alone | NEVER (cumulative, not per-event) |
## When to Use This Skill
Use when implementing any handler that revokes credits or mutates a paid-status column in response to Stripe refund or dispute events.
**Related skills:**
- For `getRefundDelta` (the G2 delta helper): `stripe-billing-master:stripe-list-pagination-previous-attributes`
- For the canonical refund helper and audit-row invariant: `stripe-billing-master:stripe-credit-audit-trail`
- For the G1 checkpoint pattern every dispute handler wraps: `stripe-billing-master:stripe-webhook-idempotency`
## Core Rules
### G2: refund delta
Use `getRefundDelta()` from `stripe-billing-master:stripe-list-pagination-previous-attributes` — that skill owns the delta-computation helper. Key guarantee: the helper returns `null` when no source is available, and the handler MUST skip revocation rather than guess.
### G7: exhaustive `shouldRestoreStatus`
```ts
const shouldRestoreMap = {
won: true,
warning_closed: true,
prevented: true,
lost: false,
needs_response: false,
under_review: false,
warning_needs_response: false,
warning_under_review: false,
charge_refunded: false,
} satisfies Record<Stripe.Dispute.Status, boolean>;
export const shouldRestoreStatus = (s: Stripe.Dispute.Status): boolean => shouldRestoreMap[s];
```
When Stripe adds a new status in a future SDK version, this object is a compile error until you add the key — forcing a conscious G5 allowlist decision.
### Credit-pack vs subscription refund
```ts
async function resolveCreditsToRevoke(charge: Stripe.Charge, refundAmount: number) {
const sessions = await stripe.checkout.sessions.list({
payment_intent: charge.payment_intent as string,
limit: 1,
expand: ["data.line_items"],
});
const session = sessions.data[0];
if (session?.mode !== "subscription") {
const pack = CREDIT_PACKS.find(p => session?.line_items?.data?.[0]?.price?.id === p.priceId);
if (pack && session.amount_total && session.amount_total > 0) {
// Proportional revocation: if they refunded 50% of the pack, revoke 50% of the credits
return Math.round(pack.credits * (refundAmount / session.amount_total));
}
}
// Subscription: 1 credit = 1 cent at cash-equivalent
return refundAmount;
}
```
Notes on the credit-pack math: proportional revocation matters because packs are bulk-priced (e.g., 1000 credits for $9 instead of $10) — a flat `refundAmount -> credits` conversion over-revokes. Always look up the originating Checkout Session to distinguish `mode: "subscription"` (cash-equivalent) from `mode: "payment"` with a known pack price ID (proportional).More General & Other skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
grill-me
mattpocock/skills
A relentless interview to sharpen a plan or design.
grill-with-docs
mattpocock/skills
A relentless interview to sharpen a plan or design, which also creates docs (ADR's and glossary) as we go.

