Вернуться к статьям

Stripe Connect Marketplace: архитектура Direct vs Express vs Custom

7 мая 2026
12 мин чтения
AI-research draft
Stripe Connect Marketplace: архитектура Direct vs Express vs Custom

Практическая архитектура маркетплейса на Stripe Connect. Когда выбирать Direct/Standard, Express или Custom, как устроить потоки денег, комиссии, онбординг, вебхуки и бухгалтерию.

Ошибиться с моделью Stripe Connect на старте — это год технического долга: мигрировать продавцов, перестраивать флоу возвратов и спорив, переписывать учёт. В этой статье разложим архитектуру маркетплейса на Stripe Connect и разницу Direct (Standard), Express и Custom так, чтобы решение можно было принять за час, а не за квартал.

Короткий ответ: если вам нужен минимальный комплаенс и продавцы сами управляют выплатами — Standard/Direct. Если важны быстрый онбординг, контроль комиссий и бренд платформы — Express с destination charges. Если требуется полный white‑label и кастомные пайплайны выплат/рисков — Custom со separate charges and transfers и своим леджером. Детали — ниже, с кодом и производственными граблями.

Когда что выбирать

Простая матрица выбора

  • Вы — каталог/лид‑генератор, продавцы самостоятельны, вам нужна только комиссия за транзакцию, а поддержку держать не хотите.

    • Выбор: Standard (Direct). Плюсы — быстрый запуск, меньше обязанностей по комплаенсу. Минусы — ограниченный контроль комиссий и UX разнится между продавцами.
  • Вы — маркетплейс с единой корзиной, возвратами через платформу, прозрачной комиссией, хотите контролировать расписание выплат.

    • Выбор: Express + destination charges (или separate + transfers в сложных сценариях). Плюсы — контроль потоков денег и бренд, упрощённый онбординг. Минусы — больше обязанностей по рискам/спорам.
  • Вы — платёжный слой под капотом SaaS/супер‑маркетплейс, нужен полный white‑label, сложные схемы сплитов, удержания эскроу, кастомный скрининг.

    • Выбор: Custom + separate charges and transfers. Плюсы — максимальная гибкость. Минусы — максимальная ответственность и время вывода в прод.

Одна инженерная шутка на дорожку: если вы не знаете, какой вариант вам нужен, почти наверняка вам пока не нужен Custom.

Архитектура потоков денег

Три базовых схемы

  1. Direct charges (на connected аккаунте)
  • Чардж создаётся на аккаунте продавца. Stripe комиссию списывает с него. Площадка видит транзакцию, но почти не влияет на выплаты.
  • Место: Standard чаще всего, но возможен и для Express/Custom.
  • Комиссию платформы удерживать сложно: нет автоматического application_fee_amount в некоторых режимах Standard; обычно её реализуют как отдельный инвойс/подписку или переходят на destination charges.
  1. Destination charges (чардж на платформе, автоперевод продавцу)
  • PaymentIntent создаётся на платформе, деньги зачисляются на баланс платформы, а затем Stripe автоматически переводит нетто‑сумму продавцу с учётом application_fee_amount.
  • Ответственность за споры/чарджбеки и процессинг — у платформы. Stripe может автоматически реверсировать трансфер при возврате/споре.
  • Удобно для Express (и Custom), позволяет удерживать комиссию прозрачно.
  1. Separate charges and transfers (раздельные чардж и трансфер)
  • Платформа создаёт чардж на себя, а затем отдельный Transfer на продавца. Вы гибко управляете таймингом перевода, частичными/отложенными выплатами, эскроу.
  • При возврате нужно вручную делать Transfer Reversal. Больше контроля = больше обязанностей.

Референс‑архитектура (Express + destination charges)

Инструменты в продакшене, которые мы видим чаще всего:

  • Клиент: веб/мобайл, Stripe Elements/Checkout, SCA/3DS встроен.
  • Бэкенд: Node.js/TypeScript, Stripe SDK; авторизация продавцов через Connect Onboarding.
  • Леджер: Postgres (двойная запись), денормализованный репортинг в ClickHouse/BigQuery.
  • Очереди: Redis + BullMQ/RabbitMQ для асинхронных выплат/реверсов.
  • Вебхуки: публичная конечная точка за Cloudflare/NGINX, валидация сигнатуры, ретраи с идемпотентностью. Для надёжности уместно вынести приём вебхуков в edge‑слой (см. наш разбор про инфраструктуру Cloudflare).
  • Мониторинг: Sentry + Prometheus + Stripe Radar сигналы модерации.

Поток:

  1. Покупатель инициирует оплату. Клиент получает client_secret для PaymentIntent.
  2. Платформа создаёт PaymentIntent с transfer_data.destination = connected аккаунт продавца и application_fee_amount = комиссия платформы.
  3. Stripe выполняет SCA/3DS, подтверждает платёж, генерит вебхуки payment_intent.succeeded/charge.succeeded.
  4. Ваш бэкенд валидирует вебхук, фиксирует транзакции в леджере, обновляет статусы заказа, выстраивает SLA на доставку.
  5. Платформа управляет возвратами. Stripe реверсирует трансфер продавцу автоматически при destination charges.

Пример кода: создание PaymentIntent c destination charges

import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2023-10-16',
});

// Суммы в центах. Продавец — connected account.
export async function createIntent({
  amountCents,
  currency,
  connectedAccountId,
  platformFeeCents,
  customerId,
}: {
  amountCents: number;
  currency: string;
  connectedAccountId: string;
  platformFeeCents: number;
  customerId?: string;
}) {
  const intent = await stripe.paymentIntents.create({
    amount: amountCents,
    currency,
    customer: customerId,
    payment_method_types: ['card'],
    capture_method: 'automatic', // для отложенного — 'manual'
    description: `Order to seller ${connectedAccountId}`,
    transfer_data: {
      destination: connectedAccountId,
    },
    application_fee_amount: platformFeeCents,
  });
  return intent.client_secret;
}

Леджер маркетплейса (двойная запись)

Внутренний леджер — не роскошь, а необходимость. Он позволяет сверять итоговые балансы с Stripe и корректно считать доход платформы.

  • Таблицы: ledger_entries (debit/credit), ledger_accounts (platform_revenue, seller_payable, fees, cash), transactions (ссылка на Stripe charge/pi).
  • Инвариант: сумма дебетов = сумма кредитов.
  • Для destination charges логируем: дебет cash (брутто), кредит seller_payable (нетто продавцу), кредит platform_revenue (комиссия), дебет fees (процессинг). Баланс с Stripe сверяется по вебхукам.

Простейший SQL‑эскиз зависимостей:

-- Упрощённо: две проводки на комиссию и выплату продавцу
insert into ledger_entries (tx_id, account, side, amount_cents, currency)
values
  (:tx, 'cash', 'debit', :amount, :cur),
  (:tx, 'platform_revenue', 'credit', :platform_fee, :cur),
  (:tx, 'seller_payable', 'credit', :amount - :platform_fee - :processing_fee, :cur),
  (:tx, 'processing_fees', 'debit', :processing_fee, :cur);

Онбординг и комплаенс: Standard vs Express vs Custom

Standard (часто называют Direct)

  • Продавец создаёт/подключает свой стандартный Stripe‑аккаунт через OAuth.
  • Своим дашбордом и выплатами управляет сам продавец, поддержка — на его стороне.
  • KYC/AML и верификация — напрямую со Stripe. Платформа почти не вовлечена.
  • Платформенная комиссия — ограниченно: надёжнее реализуется не через прямые списания, а через destination charges или абонентскую модель.

Express

  • Хостед‑онбординг от Stripe, но платформа контролирует ключевые параметры аккаунта и расписание выплат.
  • Продавец видит упрощённый Express Dashboard (бренд платформы), часть поддержки — на стороне платформы.
  • Легко удерживать комиссию через application_fee_amount.
  • Хороший баланс между скоростью запуска и контролем.

Custom

  • Полный white‑label: вы собираете KYC, загружаете документы, управляете capability (card_payments, transfers).
  • Максимальная гибкость: сложные сплиты, эскроу, собственные антифрод‑правила поверх Stripe Radar.
  • Также максимальная ответственность: поддержка, споры, отчётность налоговых форм (напр., 1099 в США), регуляторные обязанности в юрисдикциях.

Управление требованиями (requirements)

  • Любой Connect‑аккаунт имеет поля requirements.currently_due, eventually_due, past_due.
  • В проде критично синхронизировать статусы и блокировать приёмы платежей при past_due.
  • Онбординг запускается через account_links (refresh/return URL), для Custom — собственные формы + stripe.accounts.update.

Сравнение Direct (Standard) vs Express vs Custom

КритерийStandard (Direct)ExpressCustom
ОнбордингOAuth на Stripe, продавец владеет аккаунтомХостед‑онбординг, бренд платформыПолный кастом, вы собираете KYC
Контроль выплатПродавецПлатформа задаёт расписаниеПлатформа полностью контролирует
Где создаётся чарджОбычно на аккаунте продавца (direct)На платформе (destination/sep+transfer)На платформе (чаще sep+transfer)
Удержание комиссииОграниченно/опосредованноПростое через application_fee_amountЛюбая логика через transfers
Ответственность за спорыЧаще продавец (direct)Платформа (destination/sep)Платформа
Поддержка и UXРазнородный, Stripe UIЕдиный Express UIПолный white‑label
Комплаенс нагрузкаМинимальнаяСредняяВысокая
Сложность реализацииНизкаяСредняяВысокая

Примечание: для Standard с destination charges часть строк меняется (споры и комиссия на стороне платформы), но часто Standard выбирают именно ради «минимум обязанностей», то есть direct charges и слабое вмешательство платформы.

Возвраты, чарджбеки и реверсы: не перепутайте механики

  • Destination charges: при refund/dispute Stripe может автоматически реверсировать перевод продавцу. Ваш леджер должен создать контр‑проводки, но ручной Transfer Reversal обычно не нужен.
  • Separate charges and transfers: возврат денег покупателю НЕ реверсирует перевод продавцу. Нужно вызывать transfers.reversals.create на сумму возврата. Не забудьте о частичных возвратах и комиссии платформы.

Пример вебхука с реверсом трансфера для separate‑модели:

import { Request, Response } from 'express';
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, { apiVersion: '2023-10-16' });

export async function stripeWebhook(req: Request, res: Response) {
  const sig = req.headers['stripe-signature'] as string;
  let event: Stripe.Event;
  try {
    event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
  } catch (err) {
    return res.status(400).send(`Webhook Error: ${(err as Error).message}`);
  }

  if (event.type === 'charge.refunded') {
    const charge = event.data.object as Stripe.Charge;
    const transferId = charge.transfer as string | null; // Для sep+transfer может быть null, храните связь у себя

    // Находим связанный transfer у себя в БД
    const xfer = await findTransferByCharge(charge.id);
    if (xfer) {
      const refunded = charge.amount_refunded ?? 0;
      // Идемпотентность обязательна при ретраях вебхуков
      await stripe.transfers.createReversal(xfer.transferId, {
        amount: refunded,
      }, {
        idempotencyKey: `rev_${xfer.transferId}_${refunded}`,
      });
      await markTransferReversedInLedger(xfer.transferId, refunded);
    }
  }

  res.json({ received: true });
}

Что ломается в продакшене

  • Идемпотентность: любые операции, которые может триггерить повторный вебхук/ретрай клиента, — только с идемпотентными ключами. Иначе двойные возвраты и дубли выплат.
  • Порядок вебхуков: payment_intent.succeeded может прийти раньше, чем вы сохраните заказ. Стройте обработку как конечный автомат с повторяемыми шагами.
  • Негативные балансы: при волнe чарджбеков/возвратов у продавца уходит баланс в минус. Решайте заранее: удержание из будущих выплат, дебетование карты продавца, стоп продаж.
  • Конвертации и копейки: рубли → евро → доллары — округления порождают «хвосты». Леджер должен уметь учитывать остатки в минимальных единицах валют.
  • Частичный capture: при capture_method=manual следите за окном дедлайна capture и корректным распределением комиссий на «захваченную» сумму.
  • SCA/3DS: off_session платежи для подписок/отложенных списаний требуют setup_future_usage и fallback на email/ин‑апп подтверждение.
  • Capabilities и KYC‑сроки: если требования перешли в past_due, выплаты блокируются внезапно. Нужны фоновые проверки и коммуникация с продавцом.
  • Тест/боевой режимы: перепутанные ключи или stripe_account заголовок — классика. Введите принудительный отдельный проект/пайплайн для live‑ключей.
  • Отказы выплат: неверные реквизиты, изменения банка, лимиты — готовьте автоматическую реактивацию/повторные выплаты и тикеты на поддержку.

Стоимость и ROI: когда окупается контроль над платежами

Сколько стоит правильная реализация — вопрос с дельтой, зато сама дельта объясняет выбор модели.

  • Discovery и схемы потоков, оценка рисков/страны/налогов: 2–4 недели.
  • MVP (Express + destination charges, одна страна, карты): 6–10 недель разработки, плюс 2–4 недели сертификаций/юридических процедур.
  • Custom/sep+transfer с эскроу, многосторонними сплитами, сложным леджером: 12–20 недель.

Затраты по Stripe: стандартная комиссия процессинга плюс надбавка за Connect (за активные аккаунты/выплаты и др.). Чистые цифры зависят от региона и способов оплаты — проверяйте актуальные прайсы в вашем аккаунте Stripe.

Когда окупается Express/Custom:

  • Комиссия платформы > 0.5–1% оборота и/или нужен единый UX возвратов и споров — контроль начала окупаться.
  • Нужны альтернативные рельсы (банковские переводы, локальные методы, комбинированные корзины). Здесь Connect облегчает маршрутизацию. Мы нередко обсуждаем и локальные схемы вроде PIX в Бразилии — см. наш контекстный обзор Brazil: Pix vs Visa/Mastercard.
  • Требуется масштаб в нескольких странах: Express/Custom проще расширять матрицей capabilities и правилом маршрутизации валют.

Скрытые расходы, которые недооценивают:

  • Поддержка продавцов: блокировки KYC, фейлы выплат, споры — это время команды.
  • Внутренний учёт и сверки: BI/финансы захотят отчёты в разрезе дня/валют/продавцов. Готовьте пайплайн экспорта (Stripe Sigma/Reports → DWH).
  • Налоги: в США — 1099/K; в ЕС — НДС/OSS. Для Custom ответственность выше. Проконсультируйтесь с налоговыми консультантами до релиза, а не после первой проверки.

Пошаговый план внедрения (для Express)

  1. Проектирование
  • Решить про charge‑тип: для 80% сценариев достаточно destination charges.
  • Спроектировать леджер с двойной записью и событиями возвратов/реверсов.
  1. Онбординг продавцов
  • Создавать account c типом express, capabilities card_payments, transfers.
  • Генерировать account_links (refresh/return) и держать state‑машину требований.
  1. Платёжный поток
  • Создание PaymentIntent с transfer_data.destination и application_fee_amount.
  • Включить SCA, setup_future_usage для повторных платежей.
  1. Вебхуки и очереди
  • Обрабатывать payment_intent.succeeded, charge.dispute.created, charge.refunded, payout.*.
  • Идемпотентность + повторная обработка.
  1. Возвраты/споры
  • Для destination — опираться на авто‑реверс трансферов, обновлять леджер.
  • Для separate — реализовать transfer reversal.
  1. Выплаты
  • Контролировать расписание (weekly, manual), negative balance policy.
  1. Отчётность
  • Экспортировать в DWH, автоматизировать сверки по датам и валютам, SLA на закрытие периода.

Частые архитектурные вопросы

Какую модель выбрать для смешанной корзины (несколько продавцов в одном заказе)?

  • Чаще всего: на каждую группу товаров по продавцу — отдельный PaymentIntent с собственным transfer_data.destination. Если нужен один чардж с разбиением — это уже separate charges and transfers и ваш леджер обязан правильно делить комиссию/налоги.

Как брать комиссию платформы поверх подписок?

  • Используйте Billing с application_fee_percent для подписок на connected аккаунтах (Express/Custom) или application_fee_amount на инвойсах. В Standard с direct‑моделью это сделать сложнее — рассмотрите смену схемы на destination charges.

Что с альтернативными платёжными методами (банковские переводы, wallets)?

  • Выбирайте по странам: SEPA/ACH — удобны для payouts и больших чеков; локальные кошельки улучшают конверсию. В Connect нужно проверить поддержку метода для типа аккаунта и страны.

Можно ли мигрировать со Standard на Express/Custom потом?

  • Да, но это дороже, чем выбрать правильно сразу. Придётся заново онбордить продавцов, менять charge‑тип и логику возвратов/споров. Планируйте миграцию пакетами с бэкап‑планом.

Заключение

  • Standard/Direct — быстро и почти без забот, но с ограниченным контролем и монетизацией.
  • Express — оптимум для большинства маркетплейсов: понятный онбординг, прозрачный сплит, адекватная нагрузка на поддержку.
  • Custom — берите только когда точно понимаете, зачем вам полный контроль леджера и рисков.

Если вы строите долгоживущий маркетплейс, не экономьте на леджере, вебхуках и сценариях реверсов. Это окупится в первую же волну возвратов.

FAQ

Q: Можно ли в Standard удерживать комиссию платформы автоматически? A: Надёжнее это делается через destination charges или отдельные биллинговые механики. В direct‑модели Standard автоматическое удержание комиссии ограничено и зависит от схемы.

Q: Что выбрать для мгновенных выплат продавцам? A: Express или Custom. Для instant payouts проверьте доступность по стране и карточным рельсам, плюс политику рисков и negative balance.

Q: Как обработать частичный возврат при separate charges and transfers? A: Делаете refund чарджа на нужную сумму, затем создаёте transfer reversal на ту же сумму (или на пропорциональную часть), обновляете леджер.

Q: Кто отвечает за чарджбеки при destination charges? A: Платформа. Поэтому закладывайте бюджет на риски, процессы доказательств и SLA поддержки.

Q: Можно ли совмещать модели для разных сегментов продавцов? A: Да. Например, мелких вести на Express/destination, крупных — на Custom/sep+transfer. Важно изолировать логику в коде и отчётности.

Q: Как учитывать комиссии Stripe в леджере? A: Или по вебхукам balance.transaction, или по ежедневным отчётам Stripe (Reports). Комиссии — отдельный счёт расходов, связанный с чарджами и валютами.

Key takeaways

  • Выбор между Standard, Express, Custom — это баланс контроля, комплаенса и скорости запуска.
  • Для 80% маркетплейсов Express + destination charges закрывает потребности по сплитам и UX.
  • Separate charges and transfers нужны для эскроу, отложенных выплат и сложных сплитов, но требуют ручных реверсов и крепкого леджера.
  • Леджер с двойной записью, идемпотентные вебхуки и сценарии реверсов — must‑have в продакшене.
  • Планируйте поддержку KYC/проверок и негативных балансов до запуска, а не после первой бури чарджбеков.
  • Миграция между моделями возможна, но дорогая — лучше выбрать правильно на старте.

Если вы строите маркетплейс на Stripe Connect и нужна архитектура, которая переживёт реальный трафик и проверки, напишите нам — команда MTBYTE помогает спроектировать и внедрить такие системы. Свяжитесь через /contact, разберём ваш кейс и соберём реалистичный план запуска.