Stripe Connect en producción: onboarding, KYC, payouts y reservas (2026) — Cesar Ayala
← Todos los artículos

Stripe Connect en producción: onboarding, KYC, payouts y reservas (2026)

Operar Stripe Connect significa hacer onboarding con Account Links de un solo uso, vigilar el webhook account.updated hasta que el KYC pase y se activen capabilities como card_payments, y luego fijar un schedule de payout (diario, semanal, mensual o manual). El detalle: las reservas y los saldos negativos de más de 180 días son, al final, responsabilidad de tu plataforma.

Arquitectura vs operación: de qué trata este post

Hay una diferencia enorme entre diseñar un marketplace con Stripe Connect y operarlo con dinero real moviéndose todos los días. En la arquitectura de pagos de marketplace cubrí lo que decides una sola vez: los tipos de cuenta (Standard, Express, Custom) y los tipos de cargo (direct, destination). Léelo primero si todavía no sabes qué combinación vas a usar, porque este post asume que ya la tienes.

Aquí voy por lo otro: lo que pasa después de la arquitectura. El onboarding de vendedores, el KYC y las capabilities, el timing de los payouts, los pagos instantáneos, y las reservas. La arquitectura es una decisión de un día. La operación es lo que te muerde todos los días, y es donde la mayoría de los fundadores se estrellan con su primer chargeback grande.

Una disciplina se mantiene desde el post anterior y la vas a ver repetida aquí hasta el cansancio: el webhook account.updated es la fuente de la verdad, nunca un redirect ni una llamada optimista desde el cliente. Si quieres entender por qué prefiero eventos sobre polling para esto, lo desarrollé en webhooks vs polling vs API. Y si Stripe en general todavía te suena nuevo, la base de Stripe para un comercio es buen punto de partida.

La regla base de Connect: la plataforma debe recolectar la información de KYC de las cuentas conectadas y enviarla a Stripe vía API. No es opcional, y no lo hace el vendedor por su cuenta en algún portal mágico. Tú eres responsable de que esa info llegue.

La forma sana de hacerlo es delegando la captura a Stripe con onboarding hospedado: o un Account Link (una URL a la que mandas al vendedor) o los componentes embebidos de account-onboarding. El Account Link es lo más rápido de montar. En Node:

// Crea un Account Link de onboarding para una cuenta conectada
const accountLink = await stripe.accountLinks.create({
  account: connectedAccountId,
  type: 'account_onboarding',
  refresh_url: 'https://tuapp.com/connect/refresh',
  return_url: 'https://tuapp.com/connect/return',
});

// Redirige al vendedor a accountLink.url
res.redirect(accountLink.url);

Tres cosas que tienes que tener claras:

  • Las URLs de Account Link son de un solo uso. Exponen información personal, así que Stripe las quema apenas se usan o expiran. Si el vendedor abandona el flujo y vuelve, no recicles la URL: acuña una nueva. Para eso existe el refresh_url — cuando Stripe detecta que el link ya no sirve, manda al vendedor ahí, y tú generas un accountLinks.create nuevo sobre la marcha.
  • Puedes prellenar (prefill) información para ahorrarle pasos al vendedor, pero una vez que creas el Account Link o el Account Session, algunos campos quedan bloqueados para cuentas Standard/Express. Prellenar mal y después querer corregir es un dolor; valida antes.
  • El return_url no es prueba de nada. Que el vendedor regrese no significa que su KYC pasó. De eso va la siguiente sección.

Documentación oficial: identity verification.

Onboarding de un vendedor de punta a punta

  1. Crea la cuenta conectadastripe.accounts.create con el tipo que elegiste en arquitectura
  2. Genera el Account Linktype: account_onboarding, de un solo uso
  3. El vendedor completa KYC/verificaciónonboarding hospedado por Stripe; tú envías la info por API
  4. Stripe activa las capabilitiescard_payments / transfers pasan a active al cumplir requirements
  5. Primer payouttras el hold inicial más largo, luego entra al schedule
Cada paso depende del anterior; el último solo ocurre cuando las capabilities leen active.

¿Cuándo se activan realmente las capabilities? (KYC y verificación)

Aquí es donde fallan las integraciones apresuradas. Capabilities como card_payments y transfers solo se activan cuando los requirements de KYC quedan satisfechos. Volver del onboarding por el return_url no es prueba de eso. Un vendedor puede terminar el formulario, regresar contento, y seguir con la capability en inactive porque Stripe todavía está verificando un documento o porque pidió algo adicional.

La forma correcta de saber si un vendedor está listo es escuchar el webhook account.updated y leer los campos requirements y capabilities de la cuenta. No el redirect. El evento.

// Maneja account.updated y decide si el vendedor puede operar
app.post('/webhooks/stripe', (req, res) => {
  // Verifica la firma con el raw body antes de confiar en el evento
  const event = stripe.webhooks.constructEvent(req.body, req.headers['stripe-signature'], endpointSecret);
  if (event.type === 'account.updated') {
    const acct = event.data.object;
    const cardPayments = acct.capabilities?.card_payments; // 'active' | 'inactive' | 'pending'
    const dueNow = acct.requirements?.currently_due || [];
    if (cardPayments === 'active' && dueNow.length === 0) {
      // solo entonces habilitas al vendedor para cobrar
    }
  }
  res.sendStatus(200);
});

Y ojo con esto: los requirements cambian con el tiempo. No son una lista fija que llenas una vez. La regulación se actualiza de forma continua — Stripe estuvo actualizando la recolección de requirements de forma escalonada hasta el 1 de abril de 2026 — así que tienes que tratar currently_due y eventually_due como un blanco móvil. Un vendedor que ayer estaba active puede aparecer mañana con un currently_due nuevo y, si no lo cumple, perder la capability.

Mi regla, sin rodeos: no habilites a un vendedor para cobrar ni para recibir payouts hasta que la capability relevante lea active. Condiciona sobre el evento, no sobre el redirect.

Diario, semanal, mensual o manual: ¿qué schedule de payout?

El schedule de payout es configurable por cuenta conectada o como default de la plataforma. Tienes cuatro modos:

  • Diario — paga N días después del cargo. Las cuentas nuevas de EE. UU. arrancan con un rolling de ~2 días hábiles por default.
  • Semanal — un día de la semana que tú eliges.
  • Mensual — un día del mes que tú eliges.
  • Manual — no sale nada solo; tú disparas cada payout por API.

Un detalle que sorprende a todos: las cuentas nuevas suelen tener un hold más largo antes del PRIMER payout (a menudo ~7–14 días) y solo después se acomodan en el schedule rolling. No es un bug, es Stripe cubriéndose mientras la cuenta no tiene historial.

Para fijar un schedule semanal en una cuenta conectada:

// Schedule semanal con anclaje el viernes
await stripe.accounts.update(connectedAccountId, {
  settings: {
    payouts: {
      schedule: { interval: 'weekly', weekly_anchor: 'friday' },
    },
  },
});

Mi opinión: para la mayoría de los marketplaces, semanal es el default sensato. Es predecible para el vendedor (sabe que cobra los viernes) y te da una ventana para absorber refunds y disputes antes de que el dinero salga. El diario suena generoso pero te deja sin colchón cuando entra un chargeback el lunes sobre un cargo del viernes. El manual es para cuando necesitas control total sobre el riesgo y estás dispuesto a operarlo.

Documentación: payouts to connected accounts.

Schedules de payout, lado a lado

Semanal / Mensual (programado)

  • Predecible para el vendedor
  • Ventana para absorber refunds y disputes
  • Menos exposición antes de que salga el dinero
  • Default recomendado para marketplaces

Diario / Manual / Instant

  • Diario: dinero rápido, poco colchón ante chargebacks
  • Manual: control total, tú disparas cada payout
  • Instant: ~30 min, incluso fines de semana, fee ≈1.5%
  • Mueve fondos antes de cerrar tu ventana de disputes
Timing, previsibilidad y riesgo. Instant es un disparo puntual, no un schedule recurrente.

¿Deberías ofrecer pagos instantáneos (Instant Payouts)?

Los Instant Payouts mandan fondos a una tarjeta de débito o banco elegible en ~30 minutos, a cualquier hora, incluidos fines de semana y feriados, por un fee extra (≈1.5% como referencia en 2026; confirma el actual). Como plataforma, puedes dejar que tus cuentas conectadas accedan a su balance apenas un cargo es exitoso.

La llamada es un payout normal con el método cambiado:

// Payout instantáneo desde el balance de la cuenta conectada
await stripe.payouts.create(
  { amount: 5000, currency: 'usd', method: 'instant' },
  { stripeAccount: connectedAccountId }
);

Sin el method: 'instant' es un payout manual estándar.

Mi lectura, consciente del riesgo: los instant payouts son un gancho de producto buenísimo — a los vendedores les encanta cobrar el sábado — pero sacan el dinero antes de que se cierre tu ventana de refunds y disputes. Si un vendedor cobra al instante y al día siguiente le cae un chargeback, ese balance ya voló. No los ofrezcas sobre confianza pura: combínalos con reservas. Esa es exactamente la transición a la sección que más importa.

Cómo fluye el dinero en Connect

Cargo del clienteel pago entra al balance de la cuenta conectada
La reserva retiene partese aparta un colchón para cubrir refunds y disputes
Payout liberado por schedulediario, semanal, mensual o manual/instant
Llega al banco/débitoel resto del balance aterriza en la cuenta del vendedor
La reserva retiene parte del balance antes de que el payout se libere.

Lo que se les escapa a los fundadores: reservas y quién paga el saldo negativo

Esta es la sección por la que escribí el post.

Las reservas retienen parte del balance de una cuenta conectada para cubrir refunds y disputes. Están activadas por default para plataformas creadas después del 31 de enero de 2017. O sea, casi seguro las tienes encendidas y quizá ni te diste cuenta.

El riesgo que se les escapa a los fundadores es brutal: si una cuenta conectada se queda en negativo por más de 180 días, Stripe automáticamente jala de las reservas de TU PLATAFORMA para ponerla en cero. Léelo otra vez. No es que el vendedor moroso se las arregle con Stripe; al final, la plataforma es la responsable. Tú eres el backstop. Un vendedor que cobra, recibe una ola de chargebacks, se queda negativo y desaparece se convierte, a los 180 días, en una deducción de tu propio balance.

Esto se administra con reservas a nivel de cuenta conectada y controles de riesgo (Radar for Platforms). La jugada correcta es ponerle reserva a los vendedores riesgosos antes, no descubrir la responsabilidad después de que ya te pegó.

Sin rodeos: modela el peor caso de fraude y chargebacks de un vendedor dentro de tu política de reservas antes de escalar el onboarding, no después. Si tu plan es “abrimos el onboarding a todos y ya veremos”, lo que estás diciendo en realidad es “estamos dispuestos a comernos los saldos negativos de desconocidos”. Decídelo a propósito.

Documentación: connected-account reserves.

El riesgo de responsabilidad de la plataforma

DisparadorUna cuenta conectada se queda en negativo más de 180 días
Qué hace StripeJala automáticamente de las reservas de TU plataforma para ponerla en cero
Quién pagaLa plataforma — tú eres el backstop final
MitigaciónReservas por cuenta + Radar for Platforms en vendedores riesgosos
Por esto las reservas no son opcionales en tu cabeza, aunque Stripe te deje configurarlas.

Preguntas frecuentes sobre operar Connect

¿Por qué dejó de funcionar mi Account Link? Porque las URLs son de un solo uso — exponen información personal, así que Stripe las quema. Acuña una nueva vía refresh_url con accountLinks.create.

¿Por qué un vendedor puede entrar pero no cobra? Porque las capabilities (card_payments / transfers) solo se activan cuando se cumplen los requirements de KYC. Revisa requirements en el evento account.updated; casi siempre hay un currently_due pendiente.

¿Por qué el primer payout es tan lento? Las cuentas nuevas tienen un hold más largo antes del primer payout (a menudo ~7–14 días) y luego se acomodan en el schedule rolling. Es esperado.

¿Puedo simplemente apagar las reservas? Existen precisamente porque eres responsable de los saldos negativos de más de 180 días. Adminístralas, no desactives tu propia protección.

¿Cómo cambio el timing de payout de un vendedor? Con stripe.accounts.update y settings.payouts.schedule, por cuenta o como default de la plataforma.

Lánzalo pensando en las reservas

El loop operativo de Connect, completo, es este: onboarding vía Account Links → condicionar sobre las capabilities con account.updated → elegir un schedule de payout → administrar las reservas para el riesgo de saldo negativo. Cada eslabón depende del anterior, y ninguno se resuelve con un redirect optimista.

Mi convicción de cierre, después de correr esto con dinero real: en Connect la plataforma es el backstop. Por eso trato las reservas y el webhook account.updated como infraestructura de primera clase, no como pendientes para después. El día que un vendedor desaparezca en negativo, vas a agradecer haber puesto la reserva antes.

Y si llegaste hasta aquí sin haber decidido tus tipos de cuenta y de cargo, regresa a la arquitectura de pagos de marketplace primero. La operación se construye encima de esa decisión — no al revés.