Multi-vendor marketplaces require complex payment flows. Stripe Connect handles seller payouts, commissions, and compliance. At ZIRA Software, we've built marketplaces processing millions in transactions.
Database Schema
// Vendors/Sellers
Schema::create('vendors', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained();
$table->string('store_name');
$table->string('stripe_account_id')->nullable();
$table->boolean('stripe_onboarding_complete')->default(false);
$table->decimal('commission_rate', 5, 2)->default(10.00);
$table->timestamps();
});
// Products belong to vendors
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->foreignId('vendor_id')->constrained();
$table->string('name');
$table->decimal('price', 10, 2);
$table->timestamps();
});
// Orders with vendor items
Schema::create('order_items', function (Blueprint $table) {
$table->id();
$table->foreignId('order_id')->constrained();
$table->foreignId('vendor_id')->constrained();
$table->foreignId('product_id')->constrained();
$table->decimal('price', 10, 2);
$table->decimal('commission', 10, 2);
$table->timestamps();
});
Stripe Connect Onboarding
use Stripe\StripeClient;
class VendorController extends Controller
{
public function createStripeAccount(Vendor $vendor)
{
$stripe = new StripeClient(config('services.stripe.secret'));
$account = $stripe->accounts->create([
'type' => 'express',
'country' => 'US',
'email' => $vendor->user->email,
'capabilities' => [
'card_payments' => ['requested' => true],
'transfers' => ['requested' => true],
],
]);
$vendor->update(['stripe_account_id' => $account->id]);
// Create onboarding link
$link = $stripe->accountLinks->create([
'account' => $account->id,
'refresh_url' => route('vendor.stripe.refresh'),
'return_url' => route('vendor.stripe.complete'),
'type' => 'account_onboarding',
]);
return redirect($link->url);
}
}
Split Payments
public function processOrder(Order $order)
{
$stripe = new StripeClient(config('services.stripe.secret'));
// Group items by vendor
$vendorTotals = $order->items->groupBy('vendor_id')
->map(function ($items) {
return [
'vendor' => $items->first()->vendor,
'total' => $items->sum('price'),
'commission' => $items->sum('commission'),
];
});
// Create payment intent with transfers
$transfers = [];
foreach ($vendorTotals as $vendorData) {
$vendorAmount = ($vendorData['total'] - $vendorData['commission']) * 100;
$transfers[] = [
'amount' => $vendorAmount,
'destination' => $vendorData['vendor']->stripe_account_id,
];
}
$paymentIntent = $stripe->paymentIntents->create([
'amount' => $order->total * 100,
'currency' => 'usd',
'transfer_group' => "order_{$order->id}",
]);
// Create transfers after payment succeeds
foreach ($transfers as $transfer) {
$stripe->transfers->create([
'amount' => $transfer['amount'],
'currency' => 'usd',
'destination' => $transfer['destination'],
'transfer_group' => "order_{$order->id}",
]);
}
return $paymentIntent;
}
Vendor Dashboard
public function dashboard(Vendor $vendor)
{
return view('vendor.dashboard', [
'totalSales' => $vendor->orderItems()->sum('price'),
'totalCommission' => $vendor->orderItems()->sum('commission'),
'pendingOrders' => $vendor->orders()->pending()->count(),
'recentOrders' => $vendor->orders()->latest()->take(10)->get(),
]);
}
Conclusion
Multi-vendor marketplaces with Stripe Connect handle complex payment splits and vendor payouts automatically. Laravel provides the framework for robust marketplace development.
Building a marketplace? Contact ZIRA Software for multi-vendor platform development.