Skip to main content

Stripe Integration Implementation

✅ What's Been Implemented

1. StripeService (FishingLog.API/Services/StripeService.cs)

Core Stripe API wrapper service providing:

  • Payment Intents

    • CreatePaymentIntentAsync() - Create payment intents for one-time payments
    • ConfirmPaymentIntentAsync() - Confirm payment intents
    • GetPaymentIntentAsync() - Retrieve payment intent details
  • Refunds

    • CreateRefundAsync() - Process refunds for charges
  • Customers

    • CreateOrGetCustomerAsync() - Create or retrieve Stripe customers
  • Subscriptions

    • CreateSubscriptionAsync() - Create subscriptions
    • CancelSubscriptionAsync() - Cancel subscriptions (immediate or at period end)
  • Checkout Sessions

    • CreateCheckoutSessionAsync() - Create Stripe Checkout sessions for payments/subscriptions
  • Webhook Verification

    • ConstructWebhookEvent() - Verify webhook signatures

2. StripeWebhookController (FishingLog.API/Controllers/StripeWebhookController.cs)

Handles all Stripe webhook events:

Payment Events:

  • payment_intent.succeeded - Updates tournament registrations, bookings, and advertiser payments
  • payment_intent.payment_failed - Marks payments as failed

Charge Events:

  • charge.refunded - Updates refund status in database
  • charge.dispute.created - Logs disputes (can be extended for dispute handling)

Invoice Events:

  • invoice.payment_succeeded - Updates advertiser invoice status
  • invoice.payment_failed - Marks invoices as overdue

Subscription Events:

  • customer.subscription.created - Handles new subscriptions
  • customer.subscription.updated - Updates subscription status
  • customer.subscription.deleted - Handles subscription cancellations
  • customer.subscription.paused - Updates subscription to paused
  • customer.subscription.resumed - Updates subscription to active
  • customer.subscription.trial_will_end - Can trigger notifications

3. Updated AdminPaymentController

  • Real Refund Processing: Now calls Stripe API to process refunds instead of just marking in database
  • Error Handling: Proper error handling and logging
  • Audit Logging: All refunds are logged with Stripe refund IDs

4. Payment Intent Integration in Controllers ✅

TournamentController (FishingLog.API/Controllers/TournamentController.cs)

  • ✅ Payment intent creation in RegisterForTournament() method
  • ✅ Creates payment intent when RequiresPayment is true and EntryFee > 0
  • ✅ Stores StripePaymentIntentId in registration
  • ✅ Returns StripeClientSecret for frontend payment confirmation
  • ✅ Error handling with graceful fallback

CharterController (FishingLog.API/Controllers/CharterController.cs)

  • ✅ Payment intent creation in BookCharter() method
  • ✅ Creates payment intent when TotalPrice > 0
  • ✅ Stores PaymentIntentId in booking
  • ✅ Returns StripeClientSecret for frontend payment confirmation
  • ✅ Error handling with graceful fallback

AdvertiserController (FishingLog.API/Controllers/AdvertiserController.cs)

  • POST /api/advertiser/{id}/payments/top-up - Top-up payment intent endpoint
  • POST /api/advertiser/{id}/payments/subscription - Subscription checkout endpoint
  • ✅ Automatic Stripe customer creation/retrieval
  • ✅ Payment records created in database
  • ✅ Returns StripeClientSecret or checkout URL for frontend

🔧 Configuration

appsettings.json

{
"Stripe": {
"PublishableKey": "pk_test_...",
"SecretKey": "sk_test_...",
"WebhookSecret": "whsec_...",
"ApiVersion": "2025-11-17.clover"
}
}

appsettings.Development.json

Uses Stripe CLI webhook secret for local development.

🧪 Testing

Local Testing with Stripe CLI

  1. Start Stripe CLI listener:

    stripe listen --forward-to localhost:5001/api/stripe/webhook
  2. Trigger test events:

    stripe trigger payment_intent.succeeded
    stripe trigger payment_intent.payment_failed
    stripe trigger charge.refunded
  3. Check logs in your application to see webhook events being processed.

Testing Refunds

  1. Create a test payment intent
  2. Confirm the payment
  3. Use the admin API to refund:
    POST /api/admin/payments/tournament-registration/{id}/refund
    {
    "amount": 50.00,
    "reason": "Customer requested refund"
    }

✅ Integration Status

All payment intent integrations are complete! The following endpoints are ready for frontend integration:

  1. Tournament Registration - Returns StripeClientSecret when payment required
  2. Charter Booking - Returns StripeClientSecret when booking has price
  3. Advertiser Top-Up - Returns StripeClientSecret for payment confirmation
  4. Advertiser Subscription - Returns checkout URL for redirect

Frontend can use the returned StripeClientSecret values with Stripe.js to confirm payments. Webhooks will automatically update the database when payments succeed.

📋 Next Steps (Future Enhancements)

  1. Stripe Connect Integration

    • Set up connected accounts for tournament organizers
    • Handle account verification
    • Transfer funds to organizers
  2. Payment Retry Logic

    • Automatically retry failed payments
    • Notify users of payment failures
  3. Dispute Handling

    • Create Dispute entity to track disputes
    • Notify admins when disputes are created
    • Handle dispute resolution
  4. Subscription Management

    • Store Stripe customer ID in User entity
    • Link subscriptions to users
    • Handle subscription lifecycle events
  5. Email Notifications

    • Send emails on payment success/failure
    • Notify users of refunds
    • Subscription trial ending notifications

🔒 Security Notes

  • ✅ Webhook signatures are verified
  • ✅ CSRF protection disabled for webhook endpoint (not needed)
  • ✅ Request body buffering enabled for signature verification
  • ✅ All Stripe API calls use secret key from configuration
  • ⚠️ Never commit API keys to git
  • ⚠️ Use environment variables in production

📚 API Endpoints

Webhook Endpoint

  • POST /api/stripe/webhook - Receives Stripe webhook events

Payment Endpoints

  • POST /api/tournament/{id}/register - Tournament registration (returns StripeClientSecret if payment required)
  • POST /api/charter/listings/{id}/book - Charter booking (returns StripeClientSecret if price > 0)
  • POST /api/advertiser/{id}/payments/top-up - Advertiser account top-up (returns StripeClientSecret)
  • POST /api/advertiser/{id}/payments/subscription - Advertiser subscription checkout (returns checkout URL)

Admin Payment Endpoints

  • POST /api/admin/payments/tournament-registration/{id}/refund - Process refunds

🐛 Troubleshooting

Webhook Not Receiving Events

  1. Check Stripe CLI is running: stripe listen
  2. Verify webhook secret matches in appsettings
  3. Check application logs for errors
  4. Verify endpoint URL in Stripe Dashboard

Refund Fails

  1. Ensure charge ID exists in database
  2. Check Stripe API key is correct
  3. Verify charge hasn't already been refunded
  4. Check application logs for detailed error messages

Payment Intent Not Found

  1. Ensure StripePaymentIntentId is stored when creating payment
  2. Check payment intent was created successfully
  3. Verify webhook is processing the correct event type