# Pathrule Pattern: Stripe Billing (1.0.0)
# ::pathrule:package:stripe-billing

### [RULE] Always verify webhook signatures  (path: /api/stripe)
<!-- scope: folder | priority: high | strict -->

Verify the `Stripe-Signature` header with the endpoint secret, using the raw request body, before trusting any field.

- Never act on an unverified event.
- Read the webhook secret from server config, not from the request.
- Return `400` on verification failure.

---

### [RULE] Webhook handlers must be idempotent  (path: /api/stripe)
<!-- scope: folder | priority: high | advisory -->

Stripe delivers at least once, so the same event can arrive more than once.

- Record processed event IDs and skip duplicates, or make the side effect idempotent (upsert by a stable key).
- Do slow work outside the request and return `2xx` quickly so Stripe does not retry a successful delivery.

---

### [MEMORY] Checkout Sessions vs PaymentIntents  (path: /api/stripe)

Default to Stripe Checkout; reach for PaymentIntents only for fully custom flows.

- Checkout handles SCA, tax, and the payment UI for subscriptions and standard one-time payments.
- Use PaymentIntents with the Payment Element when you need a custom in-app flow.
- Drive entitlements from webhook events, not the client redirect result.

---

### [MEMORY] Stripe secret handling  (path: /supabase/functions)

Secret key and webhook signing secret live in server-side env only.

- Only the publishable key is client-safe.
- In edge or serverless functions, verify the caller and the webhook signature before any billing action.

---

### [SKILL] stripe-integration-review  (path: /)

---
name: stripe-integration-review
description: Review a Stripe billing change for security and correctness.
---

# Stripe integration review

- [ ] Webhook signature verified against the raw body before any logic
- [ ] Handler is idempotent (dedupe by event ID or idempotent side effect)
- [ ] Entitlements are driven by webhook events, not the client redirect
- [ ] Secret key and webhook secret are server-side only
- [ ] Correct API chosen (Checkout for standard, PaymentIntents for custom)
- [ ] Amounts and currency handled in minor units, no float math
- [ ] Handler returns 2xx fast and offloads slow work
