Laravel Stripe Connect
Agent Workflow (MANDATORY)
Before ANY implementation, use TeamCreate to spawn 3 agents:
- fuse-ai-pilot:explore-codebase - Check existing payment setup, Seller model
- fuse-ai-pilot:research-expert - Verify latest Stripe Connect docs via Context7
- mcp__context7__query-docs - Query specific patterns (account types, payment flows)
After implementation, run fuse-ai-pilot:sniper for validation.
Overview
Stripe Connect enables platforms and marketplaces to accept payments and pay out sellers/service providers.
| Use Case |
Example |
This Skill |
| Marketplace |
Etsy, eBay |
✅ Yes |
| On-demand services |
Uber, DoorDash |
✅ Yes |
| Crowdfunding |
Kickstarter |
✅ Yes |
| SaaS with payouts |
Substack, Teachable |
✅ Yes |
| Simple SaaS |
Netflix, Notion |
❌ Use billing |
Key Difference: Billing vs Connect
| Aspect |
Laravel Cashier |
Stripe Connect |
| Money flow |
Customer → You |
Customer → Seller (via you) |
| Accounts |
1 Stripe account |
Platform + N seller accounts |
| Use case |
Subscriptions |
Multi-party payments |
| Complexity |
Simple |
Complex |
Critical Rules
- Verify seller identity - KYC required before payouts
- Handle negative balances - Platform liable if seller can't cover refunds
- Webhook-driven - Never trust client-side for payment confirmation
- Store account IDs - Always persist
stripe_account_id on sellers
- Test with test mode - Use test account IDs before production
- Understand liability - Know who pays for disputes per account type
Architecture
app/
├── Http/
│ ├── Controllers/
│ │ └── Connect/
│ │ ├── SellerOnboardingController.php
│ │ ├── MarketplacePaymentController.php
│ │ └── PayoutController.php
│ └── Middleware/
│ └── EnsureSellerOnboarded.php
├── Models/
│ ├── Seller.php ← Connected account holder
│ └── Transaction.php ← Payment records
├── Listeners/
│ └── ConnectWebhookHandler.php
└── Services/
└── StripeConnectService.php
config/
└── services.php ← Stripe keys
routes/
└── web.php ← Webhook routes (no CSRF)
Decision Guide
Which Account Type?
Who handles customer support?
├── Seller handles everything → Standard
├── Platform handles support → Express or Custom
│ ├── Need full UI control? → Custom
│ └── Want Stripe's dashboard? → Express (recommended)
Which Payment Flow?
Who appears on customer's bank statement?
├── Seller's name → Direct charges
├── Platform's name → Destination charges (recommended)
└── Complex split? → Separate charges + transfers
Key Concepts
Reference Guide
Concepts (WHY & Architecture)
Templates (Complete Code)
Quick Reference
Create Connected Account
$account = \Stripe\Account::create([
'type' => 'express',
'country' => 'FR',
'email' => $seller->email,
'capabilities' => [
'card_payments' => ['requested' => true],
'transfers' => ['requested' => true],
],
]);
$seller->update(['stripe_account_id' => $account->id]);
Create Onboarding Link
$link = \Stripe\AccountLink::create([
'account' => $seller->stripe_account_id,
'refresh_url' => route('connect.onboarding.refresh'),
'return_url' => route('connect.onboarding.complete'),
'type' => 'account_onboarding',
]);
return redirect($link->url);
Destination Charge with Fee
$payment = \Stripe\PaymentIntent::create([
'amount' => 10000, // €100.00
'currency' => 'eur',
'payment_method' => $paymentMethodId,
'confirm' => true,
'application_fee_amount' => 1500, // €15.00 platform fee
'transfer_data' => [
'destination' => $seller->stripe_account_id,
],
]);
Check Account Status
$account = \Stripe\Account::retrieve($seller->stripe_account_id);
$isOnboarded = $account->charges_enabled && $account->payouts_enabled;
$needsInfo = !empty($account->requirements->currently_due);
Best Practices
DO
- Use Express accounts for most marketplaces
- Implement webhook handlers for all Connect events
- Store transaction records locally
- Handle
account.updated to track onboarding status
- Use idempotency keys for payment creation
- Test with Stripe CLI and test clocks
DON'T
- Enable payouts before KYC completion
- Ignore negative balance scenarios
- Skip webhook signature verification
- Hardcode Stripe account IDs
- Forget to handle dispute notifications
- Process refunds without checking seller balance
Laravel 13 Notes
Stripe Connect (stripe/stripe-php 16.x) est compatible Laravel 13. Adaptations :
- Webhook Connect : exclure
connect/webhook de PreventRequestForgery (voir [[laravel-auth]])
account.updated handler : utiliser Context::add('stripe_account', $accountId) pour propager dans la queue
- PHP 8.3 :
final readonly class pour Seller DTO et PayoutResult