safe-agentic-workflow / rules
bybren-llc/safe-agentic-workflow/.cursor/rules/16-stripe-payments.mdc
Stripe payment integration: webhooks, checkout sessions, subscriptions, idempotency, test mode safety.
Cursor rule405 starsChanged 2 months ago
- Reads credentials
---
description: "Stripe payment integration: webhooks, checkout sessions, subscriptions, idempotency, test mode safety."
globs: "core/**/billing/**,core/**/payments/**,core/**/stripe/**,**/webhook*stripe*"
alwaysApply: false
---
# Stripe Payment Rules
These rules apply when working on Stripe payment integration, webhooks, checkout flows, or subscription management.
## Test Mode Safety (CHECK FIRST)
Before ANY payment work:
- [ ] Verify `STRIPE_SECRET_KEY` starts with `sk_test_`
- [ ] Confirm test webhook secret (`whsec_...` from Stripe CLI)
- [ ] Use test card numbers only (4242 4242 4242 4242)
- [ ] Never use production keys in development
## Webhook Handler Pattern
**ALWAYS** verify webhook signatures and handle idempotency:
```python
import stripe
from fastapi import Request, HTTPException
async def handle_stripe_webhook(request: Request):
payload = await request.body()
signature = request.headers.get("stripe-signature")
try:
event = stripe.Webhook.construct_event(
payload, signature, settings.STRIPE_WEBHOOK_SECRET
)
except stripe.error.SignatureVerificationError:
raise HTTPException(status_code=400, detail="Invalid signature")
# Idempotency: check if event already processed
existing = await get_webhook_event(event.id)
if existing:
return {"status": "already_processed"}
# Process event and record
await process_event(event)
await record_webhook_event(event.id, event.type)
return {"status": "processed"}
```
## Idempotency Checklist
For ALL webhook handlers:
- [ ] Store event ID before processing
- [ ] Check for duplicate events before processing
- [ ] Use database transactions for atomicity
- [ ] Return 200 OK even on idempotency skip (Stripe retries on non-200)
## Common Webhook Events
```python
SUBSCRIPTION_EVENTS = [
"customer.subscription.created",
"customer.subscription.updated",
"customer.subscription.deleted",
"invoice.payment_succeeded",
"invoice.payment_failed",
]
```
## Local Webhook Testing
Use the Stripe CLI to forward events locally:
```bash
# Start webhook forwarding
stripe listen --forward-to localhost:8000/api/v1/webhooks/stripe
# Trigger test events
stripe trigger checkout.session.completed
stripe trigger invoice.payment_succeeded
stripe trigger customer.subscription.deleted
```
## FORBIDDEN
- Hardcoding API keys (use environment variables)
- Skipping webhook signature verification
- Processing webhooks without idempotency checks
- Using production Stripe keys in development or CI
- Ignoring failed payment events (always handle `invoice.payment_failed`)
## Evidence Template for Linear
Attach this after completing payment work:
```markdown
**Payment Testing Evidence**
- [ ] Test mode verified (`sk_test_` key)
- [ ] Webhook signature verification tested
- [ ] Idempotency tested (duplicate event handling)
- [ ] Success flow tested (card 4242...)
- [ ] Failure flow tested (card 4000 0000 0000 0002)
- [ ] Subscription lifecycle tested (create/update/cancel)
**Test Results:**
- Webhook events processed: {count}
- All flows: PASSED
```
## Key References
- **Stripe Docs**: https://stripe.com/docs
- **Webhook best practices**: https://stripe.com/docs/webhooks/best-practices
- **Payment patterns**: `patterns_library/` (search for payment/billing patterns)
- **Full skill docs**: `.claude/skills/stripe-patterns/SKILL.md`
Discussion
Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.
Posts are public.Sign in to post
No one has posted yet. Be the first.

