# Marketplace Platform Development **Meta-Description:** Multi-Vendor Marketplace bauen. Seller Management, Product Listings, Escrow Payments und Commission Handling. **Keywords:** Marketplace, Multi-Vendor, E-Commerce, Seller Management, Commission, Escrow, Platform Business --- ## Einführung **Marketplace Platforms** verbinden Käufer und Verkäufer. Von **Seller Onboarding** bis **Commission Splitting** – die technischen Herausforderungen sind komplex. Dieser Guide zeigt die Architektur und Implementation eines Multi-Vendor Marketplaces. --- ## Marketplace Architecture ``` ┌─────────────────────────────────────────────────────────────┐ │ MARKETPLACE PLATFORM ARCHITECTURE │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Stakeholders: │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Platform (You) │ │ │ │ ├── Commission on sales │ │ │ │ ├── Subscription fees │ │ │ │ └── Value-added services │ │ │ │ │ │ │ │ Sellers │ │ │ │ ├── List products │ │ │ │ ├── Receive payouts │ │ │ │ └── Manage inventory │ │ │ │ │ │ │ │ Buyers │ │ │ │ ├── Browse & purchase │ │ │ │ ├── Reviews & ratings │ │ │ │ └── Dispute resolution │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ Payment Flow: │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Buyer pays $100 │ │ │ │ ↓ │ │ │ │ Platform receives $100 (Stripe Connect) │ │ │ │ ↓ │ │ │ │ Platform takes 15% commission ($15) │ │ │ │ ↓ │ │ │ │ Seller receives $85 (after payout delay) │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ Core Features: │ │ ├── Seller Dashboard │ │ ├── Product Catalog │ │ ├── Shopping Cart │ │ ├── Checkout (Split Payments) │ │ ├── Order Management │ │ ├── Reviews & Ratings │ │ ├── Dispute Resolution │ │ └── Analytics & Reporting │ │ │ └─────────────────────────────────────────────────────────────┘ ``` --- ## Database Schema ```typescript // prisma/schema.prisma model Seller { id String @id @default(cuid()) userId String @unique user User @relation(fields: [userId], references: [id]) // Business Info businessName String businessType String // individual, company taxId String? description String? logo String? // Stripe Connect stripeAccountId String? @unique stripeOnboarded Boolean @default(false) payoutEnabled Boolean @default(false) // Settings commissionRate Float @default(0.15) // 15% payoutSchedule String @default("daily") // daily, weekly, monthly // Status status SellerStatus @default(PENDING) verifiedAt DateTime? // Relations products Product[] orders OrderItem[] payouts Payout[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } enum SellerStatus { PENDING ACTIVE SUSPENDED BANNED } model Product { id String @id @default(cuid()) sellerId String seller Seller @relation(fields: [sellerId], references: [id]) // Product Info name String slug String description String price Int // in cents compareAtPrice Int? currency String @default("EUR") // Inventory sku String? inventory Int @default(0) trackInventory Boolean @default(true) // Categorization categoryId String? category Category? @relation(fields: [categoryId], references: [id]) tags String[] // Media images ProductImage[] // Status status ProductStatus @default(DRAFT) publishedAt DateTime? // Stats viewCount Int @default(0) salesCount Int @default(0) rating Float? reviewCount Int @default(0) // Relations variants ProductVariant[] orderItems OrderItem[] reviews Review[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([sellerId, slug]) @@index([categoryId]) @@index([status]) } model Order { id String @id @default(cuid()) orderNumber String @unique // Buyer userId String user User @relation(fields: [userId], references: [id]) // Totals subtotal Int // Sum of items platformFee Int // Platform commission shippingTotal Int taxTotal Int total Int // Payment stripePaymentId String? paymentStatus PaymentStatus @default(PENDING) paidAt DateTime? // Shipping shippingAddress Json shippingMethod String? // Status status OrderStatus @default(PENDING) // Items (can be from multiple sellers) items OrderItem[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model OrderItem { id String @id @default(cuid()) orderId String order Order @relation(fields: [orderId], references: [id]) // Product productId String product Product @relation(fields: [productId], references: [id]) variantId String? // Seller sellerId String seller Seller @relation(fields: [sellerId], references: [id]) // Pricing price Int quantity Int subtotal Int // price * quantity commission Int // Platform commission sellerPayout Int // subtotal - commission // Status (per-seller fulfillment) status OrderItemStatus @default(PENDING) shippedAt DateTime? trackingNumber String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Payout { id String @id @default(cuid()) sellerId String seller Seller @relation(fields: [sellerId], references: [id]) amount Int currency String @default("EUR") status PayoutStatus @default(PENDING) stripePayoutId String? paidAt DateTime? failedAt DateTime? failureReason String? // Payout period periodStart DateTime periodEnd DateTime createdAt DateTime @default(now()) } ``` --- ## Seller Onboarding ```typescript // lib/marketplace/seller-onboarding.ts import { stripe } from '@/lib/stripe'; import { db } from '@/lib/db'; export async function createSellerAccount( userId: string, data: { businessName: string; businessType: 'individual' | 'company'; country: string; email: string; } ): Promise { // Create Stripe Connect account const account = await stripe.accounts.create({ type: 'express', country: data.country, email: data.email, business_type: data.businessType, business_profile: { name: data.businessName }, capabilities: { card_payments: { requested: true }, transfers: { requested: true } } }); // Create seller record await db.seller.create({ data: { userId, businessName: data.businessName, businessType: data.businessType, stripeAccountId: account.id, status: 'PENDING' } }); // Generate onboarding link const accountLink = await stripe.accountLinks.create({ account: account.id, refresh_url: `${process.env.NEXT_PUBLIC_URL}/seller/onboarding/refresh`, return_url: `${process.env.NEXT_PUBLIC_URL}/seller/onboarding/complete`, type: 'account_onboarding' }); return accountLink.url; } export async function completeSellerOnboarding( stripeAccountId: string ): Promise { // Check account status const account = await stripe.accounts.retrieve(stripeAccountId); if (account.charges_enabled && account.payouts_enabled) { await db.seller.update({ where: { stripeAccountId }, data: { stripeOnboarded: true, payoutEnabled: true, status: 'ACTIVE', verifiedAt: new Date() } }); } } // Webhook handler for account updates export async function handleAccountUpdated( account: Stripe.Account ): Promise { await db.seller.update({ where: { stripeAccountId: account.id }, data: { payoutEnabled: account.payouts_enabled || false, stripeOnboarded: account.details_submitted || false } }); } ``` --- ## Split Payments ```typescript // lib/marketplace/checkout.ts import { stripe } from '@/lib/stripe'; import { db } from '@/lib/db'; import { nanoid } from 'nanoid'; interface CartItem { productId: string; quantity: number; variantId?: string; } export async function createMarketplaceCheckout( userId: string, items: CartItem[], shippingAddress: any ): Promise { // Group items by seller const itemsBySeller = await groupItemsBySeller(items); // Calculate totals const { subtotal, platformFee, lineItems, transfers } = await calculateOrderTotals(itemsBySeller); // Create order const order = await db.order.create({ data: { orderNumber: `ORD-${nanoid(10).toUpperCase()}`, userId, subtotal, platformFee, shippingTotal: 0, // Calculate based on sellers taxTotal: 0, total: subtotal, shippingAddress, status: 'PENDING', items: { create: lineItems.map(item => ({ productId: item.productId, sellerId: item.sellerId, variantId: item.variantId, price: item.price, quantity: item.quantity, subtotal: item.subtotal, commission: item.commission, sellerPayout: item.sellerPayout, status: 'PENDING' })) } } }); // Create Stripe Checkout with transfers const session = await stripe.checkout.sessions.create({ mode: 'payment', customer_email: (await db.user.findUnique({ where: { id: userId } }))?.email, line_items: lineItems.map(item => ({ price_data: { currency: 'eur', unit_amount: item.price, product_data: { name: item.productName, images: item.images } }, quantity: item.quantity })), payment_intent_data: { // Split payment to sellers transfer_group: order.id, metadata: { orderId: order.id } }, success_url: `${process.env.NEXT_PUBLIC_URL}/orders/${order.id}/success`, cancel_url: `${process.env.NEXT_PUBLIC_URL}/cart`, metadata: { orderId: order.id } }); return session.url!; } async function calculateOrderTotals(itemsBySeller: Map) { const lineItems: any[] = []; let subtotal = 0; let platformFee = 0; const transfers: any[] = []; for (const [sellerId, items] of itemsBySeller) { const seller = await db.seller.findUnique({ where: { id: sellerId } }); for (const item of items) { const product = await db.product.findUnique({ where: { id: item.productId } }); if (!product) continue; const itemSubtotal = product.price * item.quantity; const commission = Math.round(itemSubtotal * (seller?.commissionRate || 0.15)); const sellerPayout = itemSubtotal - commission; subtotal += itemSubtotal; platformFee += commission; lineItems.push({ productId: product.id, productName: product.name, sellerId, variantId: item.variantId, price: product.price, quantity: item.quantity, subtotal: itemSubtotal, commission, sellerPayout, images: [] // Add product images }); // Prepare transfer for seller transfers.push({ sellerId, stripeAccountId: seller?.stripeAccountId, amount: sellerPayout }); } } return { subtotal, platformFee, lineItems, transfers }; } // After successful payment, create transfers export async function createSellerTransfers(orderId: string): Promise { const order = await db.order.findUnique({ where: { id: orderId }, include: { items: { include: { seller: true } } } }); if (!order) return; // Group payouts by seller const payoutsBySeller = new Map(); for (const item of order.items) { const current = payoutsBySeller.get(item.sellerId) || 0; payoutsBySeller.set(item.sellerId, current + item.sellerPayout); } // Create transfers for (const [sellerId, amount] of payoutsBySeller) { const seller = order.items.find(i => i.sellerId === sellerId)?.seller; if (!seller?.stripeAccountId) continue; await stripe.transfers.create({ amount, currency: 'eur', destination: seller.stripeAccountId, transfer_group: orderId, metadata: { orderId, sellerId } }); } // Update order status await db.order.update({ where: { id: orderId }, data: { paymentStatus: 'PAID', paidAt: new Date() } }); } ``` --- ## Seller Dashboard ```tsx // app/seller/dashboard/page.tsx import { getServerSession } from 'next-auth'; import { db } from '@/lib/db'; export default async function SellerDashboard() { const session = await getServerSession(); const seller = await db.seller.findUnique({ where: { userId: session!.user.id } }); const [stats, recentOrders, topProducts] = await Promise.all([ getSellerStats(seller!.id), getRecentOrders(seller!.id), getTopProducts(seller!.id) ]); return (

Seller Dashboard

{/* Stats Cards */}
{/* Recent Orders */}

Recent Orders

{/* Top Products */}

Top Products

); } async function getSellerStats(sellerId: string) { const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); const [revenue, orders, products, pendingPayout] = await Promise.all([ db.orderItem.aggregate({ where: { sellerId, order: { paidAt: { gte: thirtyDaysAgo } } }, _sum: { sellerPayout: true } }), db.orderItem.count({ where: { sellerId, createdAt: { gte: thirtyDaysAgo } } }), db.product.count({ where: { sellerId } }), db.orderItem.aggregate({ where: { sellerId, order: { paymentStatus: 'PAID' }, // Not yet paid out }, _sum: { sellerPayout: true } }) ]); return { revenue: revenue._sum.sellerPayout || 0, revenueChange: 0, // Calculate vs previous period orderCount: orders, orderChange: 0, productCount: products, pendingPayout: pendingPayout._sum.sellerPayout || 0 }; } ``` --- ## Platform Economics | Revenue Stream | Example | |---------------|---------| | **Commission** | 10-20% per sale | | **Listing Fee** | $0.20 per listing | | **Subscription** | $29/mo for premium | | **Promoted Listings** | $0.10 per click | | **Transaction Fee** | 2.9% + $0.30 | --- ## Fazit Marketplace Platform Development erfordert: 1. **Multi-Party Payments**: Stripe Connect für Split Payments 2. **Seller Management**: Onboarding und Verification 3. **Trust & Safety**: Reviews, Disputes, Moderation 4. **Scalability**: Handling vieler Verkäufer und Produkte Marketplaces sind komplex, aber hochprofitabel. --- ## Bildprompts 1. "Marketplace platform architecture diagram, buyers sellers and platform" 2. "Seller dashboard interface, revenue charts and order list" 3. "Payment flow visualization, split payment to multiple sellers" --- ## Quellen - [Stripe Connect](https://stripe.com/docs/connect) - [Marketplace Business Models](https://a16z.com/marketplace-100/) - [Sharetribe Marketplace Guide](https://www.sharetribe.com/academy/) - [Building Marketplaces](https://www.nfx.com/post/marketplace-handbook)