## Objetivo

Conectar cuentas Stripe existentes mediante OAuth `read_only` y aceptar push directo de plataformas cuando la cuenta Stripe ligada no ve la venta completa.

## Endpoints Stripe OAuth

| Endpoint | Función | Resultado esperado |
| --- | --- | --- |
| `POST /api/stripe/oauth/start?org={slug}&mode={test\|live}&lang={locale}` | preparar conexión OAuth | `redirectUrl` temporal a Stripe |
| `GET /api/stripe/oauth/start?org={slug}&mode={test\|live}&lang={locale}` | atajo con redirect inmediato | respuesta `302/307` a Stripe |
| `GET /api/stripe/oauth/callback?code=...&state=...` | callback interno OAuth | redirect al dashboard con conexión validada |

## Endpoints Beacon Connect

| Endpoint | Función | Resultado esperado |
| --- | --- | --- |
| `POST /api/platform-connect/verify-mapping` | validar `externalOrgRef` | devuelve organización Beacon resuelta |
| `POST /api/platform-connect/payments` | ingerir payment | crea/enriquece `Payment` y, si es suficiente, `Sale` |
| `POST /api/platform-connect/refunds` | ingerir refund | crea `PaymentRefund` y actualiza estado |
| `POST /api/platform-connect/disputes` | ingerir dispute | crea `PaymentDispute` y actualiza estado |

## Flujo recomendado

<Steps>
  <Step title="1) Iniciar OAuth">Llama `oauth/start` con organización y modo (`test|live`).</Step>
  <Step title="2) Validar callback">Beacon valida `state`, intercambia `code` por token y falla si el scope devuelto no incluye `read_only`.</Step>
  <Step title="3) Ingerir Stripe visible">La cuenta ligada empieza a alimentar `Payment.kind=CHARGE|TRANSFER|PAYOUT`, más enriquecimiento financiero por `balance_transactions`.</Step>
  <Step title="4) Completar el contexto de venta">Si la cuenta ligada solo ve movimiento financiero parcial, la plataforma envía Beacon Connect para completar `Sale` y contexto fiscal.</Step>
</Steps>

## Validaciones obligatorias

- `STRIPE_EXTENSION_ENABLED=true`.
- El callback OAuth debe incluir `read_only`; Beacon no trata `read_write` como fallback funcional equivalente.
- `providerEventId` es obligatorio en Beacon Connect.
- La reconciliación de `Payment` sigue: `stripeChargeId -> stripePaymentIntentId -> providerEventId -> (platformIntegrationId, externalPaymentId)`.

## Ejemplo de OAuth start

```bash
curl -X POST "https://test.beacon.pt/api/stripe/oauth/start?org=acme&mode=test&lang=es" \
  -H "Authorization: Bearer <beacon_session_token>"
```

```json
{
  "ok": true,
  "redirectUrl": "https://connect.stripe.com/oauth/authorize?...",
  "expiresAt": "2026-03-18T11:00:00.000Z"
}
```

## Ejemplo de Beacon Connect verify-mapping

```bash
curl -X POST "https://app.beacon.pt/api/platform-connect/verify-mapping" \
  -H "Authorization: Bearer <platform_secret>" \
  -H "Content-Type: application/json" \
  -d '{"externalOrgRef":"seller_org_123"}'
```

## Fallos comunes y mitigación

| Señal | Causa probable | Mitigación |
| --- | --- | --- |
| callback OAuth falla | la app Stripe no está configurada como Extension o no devuelve `read_only` | corregir configuración Stripe y reiniciar flujo |
| payment parcial sin `Sale` | visibilidad limitada en la cuenta ligada | completar por Beacon Connect |
| `429` en Beacon Connect | cuota de la integración excedida | respetar `retryAfterSec` y usar backoff exponencial con jitter |

<Tip title="Operación segura">El runtime Stripe usa siempre la clave de plataforma con `Stripe-Account`. Los tokens OAuth se conservan solo como material cifrado de auditoría.</Tip>
