使用 Stripe Connect 构建艺术家预订平台
在三年内构建艺人预订平台
在过去六年里,我构建了三个市场平台,娱乐预订领域是最有趣的——也是最棘手的——垂直市场之一。你需要处理两种截然不同的用户类型(讨厌行政工作的艺人和需要可靠性的活动策划者)、时间敏感的预订、可变定价、取消纠纷,以及永恒的问题"谁持有资金?"。让我为你讲解如何真正构建这样的平台。
现场娱乐预订市场是分散的。GigSalad 有 110,000+ 名表演者。GigMasters 仅在美国和加拿大就年收入约 4,700 万美元。Gigstarter 已在 8 个欧洲国家扩展。但大多数这些平台是在多年前用过时的技术栈构建的,如果从第一天就用 Stripe Connect 处理支付架构,就有真正的机会构建更好的东西。

目录
- 理解双边市场模式
- 选择技术栈
- 艺人目录的数据建模
- 搜索、过滤和发现
- Stripe Connect:支付骨干
- 预订流程架构
- 处理纠纷、取消和退款
- 实际有效的盈利模式
- 建立信任:评论、验证和托管
- 性能和扩展注意事项
- 常见问题
理解双边市场模式
双边市场在其 DNA 中内置了一个先有鸡还是先有蛋的问题。你需要艺人来吸引客户,需要客户来吸引艺人。在你写一行代码之前,你需要决定先发展哪一方。
对于娱乐预订,我几乎总是建议先发展供给方(艺人)。原因是:艺人有动力在任何可能带来演出的地方被列出。另一方面,除非已经有大量人才可以浏览,活动策划者不会访问你的平台。
核心用户旅程
艺人端:
- 注册并创建个人资料(简历、照片、视频、音频样本)
- 设置可用性、定价和服务区域
- 收到预订询问或回应演出发布
- 接受预订并在活动后获得付款
- 通过评论建立声誉
客户端:
- 按流派、位置、日期和预算搜索艺人
- 查看资料、观看演示视频、收听样本
- 发送询问或直接预订
- 通过平台付款(资金在托管中)
- 活动后留下评论
平台位于中间,促进发现、交流、支付和信任。
选择技术栈
这是我有强烈看法的地方。对于这样的市场,你需要一个能够很好地处理动态内容、支持实时功能(消息、可用性更新)并给予你灵活性来构建自定义预订逻辑的栈。
| 组件 | 推荐 | 原因 |
|---|---|---|
| 前端 | Next.js (App Router) | SSR 用于艺人资料的 SEO,React 用于交互式预订流程 |
| 后端 API | Next.js API Routes 或独立 Node.js 服务 | Stripe webhooks、预订逻辑、身份验证 |
| 数据库 | PostgreSQL (via Supabase or Neon) | 关系数据非常适合市场模式 |
| CMS | Sanity 或 Payload CMS | 艺人资料需要带媒体的结构化内容 |
| 身份验证 | Clerk 或 NextAuth.js | 基于角色的身份验证(艺人 vs. 客户端 vs. 管理员) |
| 搜索 | Meilisearch 或 Algolia | 跨流派、位置、价格的快速分面搜索 |
| 支付 | Stripe Connect | 为市场支付而专门构建 |
| 文件存储 | Cloudflare R2 或 AWS S3 | 音频样本、视频、宣传照片 |
| 托管 | Vercel 或 Cloudflare Pages | 用于快速艺人资料加载的边缘渲染 |
如果你有兴趣走 Next.js 开发 的路线,那是我对大多数团队的推荐。服务器组件用于 SEO 关键的艺人目录页面和客户端组件用于交互式预订表单的组合是难以比拟的。
对于想要用于目录部分的超快速静态页面和用于预订的动态岛的团队,Astro 也值得考虑——特别是如果平台的目录端是内容繁重的。

艺人目录的数据建模
尽早正确设计数据模型可以为你节省几个月的重构时间。以下是我发现适用于娱乐市场的方法:
-- 核心艺人资料
CREATE TABLE artists (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
stripe_account_id TEXT, -- Stripe Connect 账户
display_name TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL,
bio TEXT,
headline TEXT,
profile_image_url TEXT,
base_price_cents INTEGER,
price_type TEXT CHECK (price_type IN ('per_hour', 'per_event', 'custom')),
travel_radius_miles INTEGER,
is_verified BOOLEAN DEFAULT FALSE,
is_featured BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- 流派/分类标签(多对多)
CREATE TABLE artist_genres (
artist_id UUID REFERENCES artists(id),
genre_id UUID REFERENCES genres(id),
PRIMARY KEY (artist_id, genre_id)
);
-- 服务区域
CREATE TABLE artist_service_areas (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
artist_id UUID REFERENCES artists(id),
city TEXT,
state TEXT,
country TEXT,
lat DECIMAL(10, 8),
lng DECIMAL(11, 8)
);
-- 可用性日历
CREATE TABLE artist_availability (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
artist_id UUID REFERENCES artists(id),
date DATE NOT NULL,
status TEXT CHECK (status IN ('available', 'booked', 'blocked')),
UNIQUE (artist_id, date)
);
-- 媒体资产
CREATE TABLE artist_media (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
artist_id UUID REFERENCES artists(id),
media_type TEXT CHECK (media_type IN ('image', 'video', 'audio')),
url TEXT NOT NULL,
thumbnail_url TEXT,
title TEXT,
sort_order INTEGER DEFAULT 0
);
注意 artists 表上的 stripe_account_id。这是来自 Stripe Connect 的连接账户 ID——你每次支付都需要它。稍后详述。
重要的分类
根据 GigSalad、ShowBird(8,000+ 艺人跨越 45+ 分类)和 StarClinch(14 个分类、17,000+ 艺人)等平台的运作情况,以下是驱动最多预订的分类:
- 现场乐队(婚礼乐队、翻唱乐队、爵士乐团)
- 独奏音乐家(吉他手、钢琴家、小提琴手)
- DJ
- 歌手和歌唱家
- 古典乐团(弦乐四重奏、管弦乐队)
- 致敬表演
- 喜剧演员
- 魔术师和综艺演员
- 名人出场
- MC 和主持人
不要试图在发布时覆盖所有东西。选择 3-4 个分类,主导一个地理区域,然后扩展。
搜索、过滤和发现
搜索是任何目录市场的成败关键。如果客户无法在 30 秒内找到合适的艺人,他们会离开。
必要的搜索过滤器
- 流派/分类:带子类别的多选
- 位置:基于半径的地理搜索("奥斯汀 50 英里内的爵士乐队")
- 日期可用性:仅显示在客户活动日期可用的艺人
- 价格范围:带有最小/最大值的滑块
- 评分:最低星级评分过滤器
- 仅验证:经过验证的艺人切换
对于搜索引擎本身,我会选择 Meilisearch 而不是 Algolia 用于新构建。它是开源的、可自托管的,分面搜索非常出色。Algolia 也有效,但随着索引增长成本增加很快——在他们的付费计划中,每 1,000 次搜索请求需要 $1+。
// 示例:艺人搜索的 Meilisearch 查询
const results = await searchClient.index('artists').search(query, {
filter: [
`genres IN ["jazz", "blues"]`,
`base_price_cents >= 15000`,
`base_price_cents <= 75000`,
`_geoRadius(30.2672, -97.7431, 80467)`, // 距奥斯汀 50 英里
],
sort: ['rating:desc', 'booking_count:desc'],
facets: ['genres', 'price_range', 'rating'],
hitsPerPage: 20,
});
日期可用性是最棘手的过滤器。你不想将可用性数据推送到搜索索引并保持同步。相反,从 Meilisearch 获取更广泛的集合,然后在应用层使用数据库查询按可用性过滤。这是额外的步骤,但它保持了搜索索引的整洁。
Stripe Connect:支付骨干
这是真实情况的开始。Stripe Connect 是双边娱乐市场的正确选择。我已经评估了替代方案(PayPal for Marketplaces、Adyen for Platforms、Mangopay),Stripe Connect 在开发者体验、文档和全球覆盖方面获胜。
哪种 Stripe Connect 类型?
Stripe 提供三种 Connect 账户类型。对于艺人预订平台,以下是分解:
| 账户类型 | KYC 负担 | 仪表板访问 | 最适合 |
|---|---|---|---|
| 标准 | Stripe 处理 KYC | 艺人获得完整 Stripe 仪表板 | 艺人需要控制的平台 |
| 快速 | Stripe 处理 KYC | 有限、嵌入式仪表板 | 大多数市场(推荐) |
| 自定义 | 你处理 KYC | 无——你构建一切 | 白标平台 |
选择快速账户。艺人快速上线(Stripe 处理身份验证),他们获得有限仪表板来查看支付,而你保持对支付流程的控制。自定义账户很过度,除非你构建白标解决方案。
将艺人注册到 Stripe Connect
// 为新艺人创建 Stripe Connect 快速账户
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function createConnectAccount(artistId: string, email: string) {
const account = await stripe.accounts.create({
type: 'express',
email,
capabilities: {
card_payments: { requested: true },
transfers: { requested: true },
},
business_type: 'individual',
metadata: {
artist_id: artistId,
},
});
// 存储账户 ID
await db.artists.update({
where: { id: artistId },
data: { stripe_account_id: account.id },
});
// 生成入职链接
const accountLink = await stripe.accountLinks.create({
account: account.id,
refresh_url: `${process.env.APP_URL}/artists/onboarding/refresh`,
return_url: `${process.env.APP_URL}/artists/onboarding/complete`,
type: 'account_onboarding',
});
return accountLink.url;
}
处理预订支付
这里的关键概念是目标地收费。客户为你的平台付款,Stripe 自动分割资金——你的平台费用保留在你这里,其余部分进入艺人的连接账户。
export async function createBookingPayment(
bookingId: string,
amountCents: number,
artistStripeAccountId: string,
platformFeePercent: number = 15
) {
const platformFeeCents = Math.round(amountCents * (platformFeePercent / 100));
const paymentIntent = await stripe.paymentIntents.create({
amount: amountCents,
currency: 'usd',
application_fee_amount: platformFeeCents,
transfer_data: {
destination: artistStripeAccountId,
},
metadata: {
booking_id: bookingId,
},
// 保留电荷——不要立即捕获(类似托管的行为)
capture_method: 'manual',
});
return paymentIntent;
}
注意 capture_method: 'manual'。这对预订平台至关重要。在预订确认时授权收费,但在接近活动日期或活动发生后不要捕获(实际扣取资金)。这为你提供了没有实际托管的类似托管功能。
重要限制:Stripe 上的手动捕获必须在授权后 7 天内捕获。对于更远的活动,你需要不同的方法——立即收取定金并在活动接近时收取余款,或使用 Stripe 的独立收费和转账模式,其中你立即向客户收费但延迟向艺人的转账。
Stripe Connect 定价(2025)
Stripe 当前的 Connect 费用:
- 标准处理:2.9% + $0.30 每笔交易
- Connect 费用:额外 0.25% + $0.25 每笔支付给连接账户(快速/自定义)
- 即时支付:支付金额的 1%(可选,艺人喜欢这个)
所以在 $2,000 预订、15% 平台费($300)的情况下,数学看起来像:
- 客户支付:$2,000
- Stripe 处理:约 $58.30 (2.9% + $0.30)
- 平台费:$300
- Connect 支付费:约 $5.25 ($1,700 的 0.25% + $0.25)
- 艺人接收:约 $1,636.45
你需要明确说明谁承担 Stripe 费用。大多数平台要么将其纳入平台费,要么作为"服务费"传递给客户。
预订流程架构
这是我发现对娱乐平台有效的预订流程:
客户搜索 → 查看艺人资料 → 检查可用性 →
发送询问(可选)→ 提交预订请求 →
艺人审查并接受 → 客户的卡被授权 →
活动发生 → 平台捕获支付 → 艺人获得支付
询问 vs. 即时预订辩论
一些平台(如 GigSalad)使用询问优先模型,其中客户发送消息并获得自定义报价。其他平台允许以列出的价格即时预订。我的建议?支持两者。
- 即时预订:对于有明确、固定定价的艺人(例如,"DJ 4 小时:$800")。更高的转化率。
- 询问/报价:对于定制活动(例如,"10 人乐队参加公司庆典")。更高的平均预订价值。
让艺人在他们的设置中选择他们喜欢的模型。
预订的状态机
预订需要明确的状态。我使用状态机模式:
const BOOKING_STATES = {
INQUIRY: 'inquiry', // 客户发送了消息
QUOTED: 'quoted', // 艺人发送了价格
PENDING: 'pending', // 客户提交了预订(等待艺人)
ACCEPTED: 'accepted', // 艺人接受了
PAYMENT_AUTHORIZED: 'authorized', // 卡被授权
CONFIRMED: 'confirmed', // 双方确认
IN_PROGRESS: 'in_progress', // 活动正在进行
COMPLETED: 'completed', // 活动完成,支付已捕获
CANCELLED: 'cancelled', // 任何一方取消
DISPUTED: 'disputed', // 客户提出纠纷
REFUNDED: 'refunded', // 退款已发行
} as const;
每个状态转换都会触发特定操作:电子邮件、Stripe 操作、日历更新等。
处理纠纷、取消和退款
这是没人想思考的部分,但如果你不计划它,它会吞噬你。
取消政策层级
让艺人从预定义的层级设置自己的取消政策:
| 政策 | 30+ 天前 | 14-30 天 | 7-14 天 | 少于 7 天 |
|---|---|---|---|---|
| 灵活 | 全额退款 | 全额退款 | 50% 退款 | 无退款 |
| 温和 | 全额退款 | 50% 退款 | 25% 退款 | 无退款 |
| 严格 | 50% 退款 | 25% 退款 | 无退款 | 无退款 |
GEM 等平台使用托管金库方法——资金一直被保留到活动完成。你可以使用 Stripe 的独立收费和转账近似:立即向客户收费,但仅在活动后转账给艺人。这为你提供了对退款时间的完全控制。
艺人不出现
噩梦情景。如果艺人不出现,你需要:
- 立即全额退款给客户
- 如果已支付艺人,则扣除艺人的连接账户(Stripe Connect 支持反向转账)
- 标记艺人的账户
- 可能从平台保险基金向客户赔偿
构建报告系统,客户可以在活动后 24 小时内标记不出现。
实际有效的盈利模式
根据 2025 年顶级平台的运作情况:
| 模式 | 示例 | 优点 | 缺点 |
|---|---|---|---|
| 每次预订佣金 | 10-20% 平台费 | 收入随预订扩展 | 艺人讨厌高费用,离线平台 |
| 订阅层级 | Gigstarter:免费 / €9.99/月 / €14.95/月 | 可预测的经常性收入 | 难以向新艺人销售 |
| 线索费 | 按收到的询问付费 | 艺人摩擦力低 | 如果线索不转化可能感觉不诚实 |
| 精选列表 | GigMasters:$30-40/月 用于 Pro/Featured | 简单的追加销售 | 可能削弱搜索质量 |
| 混合 | 免费列表 + 佣金 + 高级层级 | 多个收入流 | 复杂性 |
我会从佣金模式开始(艺人端 12-15% 平台费、客户端 5-8% 服务费),一旦你有了动力就添加订阅层级。平台的总取代 17-23% 符合行业标准。
建立信任:评论、验证和托管
在市场中信任是一切,当有人为他们从未见过现场表演的婚礼乐队支付 $2,000+ 时。
验证级别
- 电子邮件验证:基本,每个人都获得这个
- 身份验证:政府 ID 检查(Stripe Connect 在入职期间处理这个)
- 背景检查:第三方服务如 Checkr
- 平台验证:你的团队的手动审查(StarClinch 通过专门验证人员做这个)
审查系统
仅允许来自完成预订的评论。这防止了虚假评论并确保每个评论都代表实际交易。显示聚合评分和个别评论详情。
// 仅在预订完成时创建评论
async function submitReview(bookingId: string, rating: number, text: string) {
const booking = await db.bookings.findUnique({ where: { id: bookingId } });
if (booking.status !== 'completed') {
throw new Error('仅可以审查已完成的预订');
}
if (booking.reviewed_at) {
throw new Error('预订已被审查');
}
return db.reviews.create({
data: {
booking_id: bookingId,
artist_id: booking.artist_id,
client_id: booking.client_id,
rating,
text,
},
});
}
性能和扩展注意事项
艺人资料页面是你最高流量的页面,也是 SEO 最重要的页面。每个艺人资料本质上是一个应该为"在芝加哥寻租爵士乐队"的搜索排名的登陆页面。
SSR + ISR 策略
使用 Next.js,对艺人资料使用增量静态再生:
// app/artists/[slug]/page.tsx
export async function generateStaticParams() {
const artists = await db.artists.findMany({
select: { slug: true },
where: { is_active: true },
});
return artists.map((a) => ({ slug: a.slug }));
}
export const revalidate = 3600; // 每小时重新验证
这为你提供了具有新鲜数据的静态页面性能。资料浏览、定价和可用性在下一个再验证周期更新。
对于搜索/目录页面,SSR 更有意义,因为内容根据过滤器和位置变化。使用带 Suspense 的流来立即显示页面 shell,同时搜索结果加载。
如果你在为这种项目权衡不同框架,我们的团队对 Next.js 和 Astro 都有深入经验——正确的选择取决于你的预订流程需要多动态与目录有多内容繁重。
CDN 和媒体优化
艺人上传高分辨率照片和视频。你需要:
- 图像优化管道(Next.js 图像组件 + Cloudflare 图像或 imgix)
- 专用服务上的视频托管(Mux、Cloudflare Stream 或 Bunny Stream)
- 音频波形生成和流(前端上的 WaveSurfer.js)
不要提供原始上传。通过服务器端处理所有内容到优化的格式。
常见问题
构建艺人预订平台需要多少成本? 包括艺人资料、搜索、预订流程和 Stripe Connect 集成的基本 MVP 通常使用经验丰富的开发团队运行 $40,000-$80,000,或 3-5 个月的构建时间。具有消息传递、移动应用和高级搜索的全功能平台可以运行 $150,000+。如果你想讨论具体情况,请查看我们的定价页面,了解我们如何为市场项目定范围。
为什么使用 Stripe Connect 而不是手动构建支付拆分? Stripe Connect 处理困难部分:40+ 个国家的艺人 KYC/身份验证、美国艺人收入超过 $600 的 1099 税务报告、自动支付计划和退款处理。自己构建这个会需要专门团队 6+ 个月并暴露你于监管风险。每次支付的 0.25% + $0.25 费用绝对值得。
娱乐预订平台的典型佣金率是多少? 大多数平台在艺人端收费 10-20%,客户端服务费 5-10%。GigSalad 和 GigMasters 在此范围内运作。Gigstarter 值得注意的是零佣金并通过订阅层级(€9.99-€14.95/月)货币化。你的理想费率取决于你的市场——婚礼娱乐可以维持比酒吧演出更高的佣金。
你如何处理艺人可用性并防止重复预订? 实现一个基于日历的可用性系统,其中艺人将日期标记为可用、已预订或已阻止。当预订确认时,自动阻止该日期。在 (artist_id, date) 上使用数据库级别唯一约束来防止竞争条件。对于每天做多个活动的艺人(如 DJ),改用时间段而不是整天块向可用性模型添加时间段。
我应该构建一个无头 CMS 驱动的目录还是完全自定义数据库? 混合方法效果最好。使用无头 CMS 用于编辑内容(博客文章、城市指南、驱动 SEO 流量的分类登陆页面)和自定义 PostgreSQL 数据库用于交易数据(预订、支付、可用性、评论)。尝试通过 CMS 运行预订逻辑是一个痛苦的配方。
我如何在我的平台上获得前 100 名艺人? 直接外展有效。从公共音乐家目录、婚礼供应商网站和本地活动列表中抓取。用明确的价值主张给艺人发电子邮件——免费列表、无预付成本,你将为他们驱动预订。为前 50 名艺人提供"创始成员"徽章和永久降低的佣金率。与本地音乐学校和场地合作。前 100 名是手动工作,句号。
多币种国际支付呢? Stripe Connect 支持 40+ 个国家的支付和 135+ 种货币。当德国艺人被美国客户预订时,Stripe 自动处理货币转换。你会向 Stripe 支付其外汇费用(大约标准处理之上 1%),但这比自己构建多币种支持便宜得多。在客户的货币中设置你的平台费用,让 Stripe 处理向艺人本地货币的转换。
我如何防止双边市场欺诈? 多层:艺人的 Stripe Connect 内置身份验证、客户端支付欺诈检测的 Stripe Radar、高价值预订的手动审查(超过 $5,000)、速率检查(标记快速创建许多预订的账户),以及在艺人支付前的保留期(活动完成后 3-7 天)。保留期是你最大的保护——它给客户时间在资金离开你的平台之前报告问题。