Stripe Integration
Stripe payment integration covering customer creation, subscription management, webhook handling, billing portal, and test mode
Overview
The backend service handles all Stripe integration including customer management, subscription plans, checkout, invoicing, and webhook processing.
Customer Creation
# backend/api/infrastructure/externals/stripe_resolver.py
async def create_stripe_customer(email: str, name: str, tenant_id: str) -> str:
customer = await stripe.Customer.create_async(
email=email,
name=name,
metadata={"tenant_id": tenant_id}
)
return customer.idSubscription Management
Trial Subscription
async def create_trial_subscription(tenant_id: str, price_id: str, customer_id: str):
subscription = await stripe.Subscription.create_async(
customer=customer_id,
items=[{"price": price_id}],
payment_behavior="default_incomplete",
metadata={"tenant_id": tenant_id}
)
# Updates tenant with subscription_id, is_trial=True, trial_end_atCheckout Session
curl -X POST http://localhost:8000/api/v1/checkout/tenant/subscription \
-H "Authorization: Bearer <token>" \
-d '{"price_id": "price_abc123"}'Webhook Handling
Stripe sends webhooks to POST /api/v1/stripe/webhook. The service handles:
| Event | Action |
|---|---|
checkout.session.completed | Activate subscription |
customer.subscription.updated | Sync subscription status |
customer.subscription.deleted | Downgrade to free plan |
customer.subscription.trial_will_end | Send trial-ending notification |
invoice.payment_succeeded | Verify active status |
invoice.payment_failed | Handle payment failure |
@router.post("/stripe/webhook")
async def handle_stripe_webhook(request: Request):
payload = await request.body()
sig_header = request.headers.get("stripe-signature")
event = stripe.Webhook.construct_event(payload, sig_header, WEBHOOK_SECRET)
# Route to handler based on event.typeDormant Tenant Detection
When a trial expires without payment:
- Celery task
check_expired_trialsruns hourly - Stripe webhook
customer.subscription.updatedwithstatus=incomplete_expired - Tenant set to
is_dormant=True,is_trial=False
Reactivation options:
- Add payment method: Stripe SetupIntent flow
- Downgrade to free:
POST /api/v1/billing/subscription/downgrade-to-free
Test Mode
For local development, use Stripe test keys:
STRIPE_API_KEY=pk_test_...
STRIPE_WEBHOOK_SECRET=whsec_test_...Use the fake-smtp container for email testing (Mailhog at port 1083).
