trading-platform/docs/02-definicion-modulos/OQI-005-payments-stripe/requerimientos/RF-PAY-008-spei.md
rckrdmrd a7cca885f0 feat: Major platform documentation and architecture updates
Changes include:
- Updated architecture documentation
- Enhanced module definitions (OQI-001 to OQI-008)
- ML integration documentation updates
- Trading strategies documentation
- Orchestration and inventory updates
- Docker configuration updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 05:33:35 -06:00

19 KiB

id title type status priority epic project version created_date updated_date
RF-PAY-008 Sistema de Depositos via SPEI Requirement Draft Alta OQI-005 trading-platform 1.0.0 2026-01-04 2026-01-04

RF-PAY-008: Sistema de Depositos via SPEI

Version: 1.0.0 Fecha: 2026-01-04 Estado: Draft Prioridad: P1 (Alta) Story Points: 8 Epica: OQI-005


Descripcion

El sistema debe permitir a los usuarios en Mexico realizar depositos utilizando SPEI (Sistema de Pagos Electronicos Interbancarios), el sistema de transferencias bancarias instantaneas del pais. Se integrara con un agregador de pagos (Stripe Mexico, Conekta u OpenPay) para generar CLABEs virtuales unicas por usuario y reconciliar automaticamente los depositos recibidos.


Objetivo de Negocio

  • Capturar mercado mexicano con metodo de pago preferido (85% de transferencias)
  • Reducir costos de transaccion vs tarjetas (1-2% vs 3.5%)
  • Eliminar chargebacks (SPEI es irreversible)
  • Ofrecer alternativa para usuarios sin tarjeta de credito
  • Aumentar ticket promedio (SPEI permite montos mayores)

Casos de Uso

  1. Deposito Simple: Usuario transfiere $5,000 MXN desde su banca en linea a su CLABE virtual
  2. Primer Deposito: Usuario obtiene su CLABE unica y realiza primera transferencia
  3. Deposito Recurrente: Usuario guarda CLABE como beneficiario frecuente en su banco
  4. Reconciliacion: Sistema detecta deposito y acredita USD equivalente automaticamente
  5. Notificacion: Usuario recibe push/email confirmando deposito procesado

Integracion con Agregadores

Opciones de Agregador

Agregador CLABE Virtual Fee Tiempo Integracion
Stripe MX Si 1% + $3 MXN 2-3 semanas
Conekta Si 1.2% + $4 MXN 1-2 semanas
OpenPay Si 0.9% + $2.5 MXN 2-3 semanas

Recomendado: Stripe MX por consistencia con otros metodos de pago.


Requisitos Funcionales

RF-PAY-008.1: Generacion de CLABE Virtual

DEBE:

  1. Generar CLABE de 18 digitos unica por usuario
  2. Asociar CLABE a userId en tabla spei_references
  3. CLABE permanente (no expira)
  4. Mostrar en UI con opcion de copiar
  5. Incluir nombre del beneficiario estandarizado

Formato CLABE:

Banco (3) + Plaza (3) + Cuenta (11) + Digito verificador (1)

Ejemplo: 646180157000001234
         ^^^                  Banco: STP (646)
            ^^^               Plaza: 180
               ^^^^^^^^^^^    Cuenta unica por usuario
                          ^   Digito verificador

Modelo de datos:

@Entity({ name: 'spei_references', schema: 'billing' })
class SpeiReference {
  id: string;              // UUID
  userId: string;          // FK a users (UNIQUE)
  walletId: string;        // FK a wallets
  clabe: string;           // CLABE 18 digitos (UNIQUE)
  beneficiaryName: string; // "TRADING PLATFORM/USER123"
  bankName: string;        // "STP" o banco del agregador
  isActive: boolean;       // true
  createdAt: Date;
  updatedAt: Date;
}

RF-PAY-008.2: Recepcion de Depositos

DEBE:

  1. Recibir webhook del agregador cuando llega transferencia
  2. Validar firma del webhook
  3. Identificar usuario por CLABE destino
  4. Crear registro en spei_deposits
  5. Procesar conversion y acreditacion

Datos del webhook:

{
  "event": "spei.incoming_transfer",
  "data": {
    "id": "tr_xxx",
    "clabe_destino": "646180157000001234",
    "clabe_origen": "012180001234567890",
    "monto": 5000.00,
    "concepto": "DEPOSITO TRADING",
    "referencia_numerica": "1234567",
    "nombre_ordenante": "JUAN PEREZ",
    "rfc_ordenante": "XAXX010101000",
    "fecha_operacion": "2026-01-04T10:30:00Z"
  }
}

RF-PAY-008.3: Conversion MXN a USD

DEBE:

  1. Obtener tipo de cambio actual MXN/USD
  2. Usar tipo de cambio del Banco de Mexico + spread
  3. Calcular USD equivalente
  4. Acreditar al wallet en USD
  5. Registrar tipo de cambio usado

Calculo:

USD_Amount = MXN_Amount / (Exchange_Rate * (1 + spread))

Ejemplo (spread 0.5%):
$5,000 MXN / (17.50 * 1.005) = $284.21 USD

RF-PAY-008.4: Reconciliacion Automatica

DEBE:

  1. Procesar depositos automaticamente (sin intervencion manual)
  2. Manejar depositos duplicados (idempotencia)
  3. Rechazar depositos de CLABEs no registradas
  4. Alertar sobre depositos anomalos (montos muy altos)
  5. Generar reporte diario de reconciliacion

Estados de Deposito:

RECEIVED   → Webhook recibido, validando
PROCESSING → Conversion en proceso
COMPLETED  → Acreditado al wallet
FAILED     → Error en procesamiento
REJECTED   → CLABE no encontrada / limite excedido

RF-PAY-008.5: Notificaciones

DEBE:

  1. Push notification inmediata al recibir deposito
  2. Email de confirmacion con detalles
  3. Mostrar en historial de transacciones
  4. Incluir tipo de cambio usado

Contenido de notificacion:

Asunto: Deposito SPEI recibido - $5,000 MXN

Has recibido un deposito SPEI:
- Monto: $5,000.00 MXN
- Equivalente: $284.21 USD (TC: 17.59)
- Referencia: 1234567
- Fecha: 4 de enero 2026, 10:30 AM

Tu nuevo saldo es: $534.21 USD

Modelo de Datos

Tabla: spei_deposits

@Entity({ name: 'spei_deposits', schema: 'billing' })
class SpeiDeposit {
  id: string;                    // UUID
  userId: string;                // FK a users
  walletId: string;              // FK a wallets
  speiReferenceId: string;       // FK a spei_references
  status: SpeiDepositStatus;     // received, processing, completed, failed, rejected

  // Datos SPEI
  clabeOrigen: string;           // CLABE del ordenante
  clabeDestino: string;          // CLABE del usuario
  montoMxn: Decimal;             // Monto en MXN
  concepto: string;              // Concepto de la transferencia
  referenciaNumerica: string;    // Referencia numerica (7 digitos)
  nombreOrdenante: string;       // Nombre del que envia
  rfcOrdenante?: string;         // RFC del ordenante
  fechaOperacion: Date;          // Fecha/hora de la operacion

  // Conversion
  montoUsd: Decimal;             // Monto convertido a USD
  tipoCambio: Decimal;           // Tipo de cambio usado
  spreadAplicado: Decimal;       // Spread aplicado (0.005)

  // Proveedor
  providerRef: string;           // ID en Stripe/Conekta/OpenPay
  providerData?: object;         // Datos raw del proveedor

  // Timestamps
  createdAt: Date;
  processedAt?: Date;
  updatedAt: Date;
}

enum SpeiDepositStatus {
  RECEIVED = 'received',
  PROCESSING = 'processing',
  COMPLETED = 'completed',
  FAILED = 'failed',
  REJECTED = 'rejected'
}

Flujo de Deposito SPEI

+-------------+     +-------------+     +-------------+     +-------------+     +-------------+
|   Usuario   |     |  Banco MX   |     |  Agregador  |     |   Backend   |     |   Wallet    |
+------+------+     +------+------+     +------+------+     +------+------+     +------+------+
       |                   |                   |                   |                   |
       | 1. Obtener CLABE  |                   |                   |                   |
       |------------------>|                   |                   |                   |
       |                   |                   |                   |                   |
       |<------------------|                   |                   |                   |
       | CLABE:            |                   |                   |                   |
       | 646180157000001234|                   |                   |                   |
       |                   |                   |                   |                   |
       | 2. Accede a banca |                   |                   |                   |
       | en linea          |                   |                   |                   |
       |------------------>|                   |                   |                   |
       |                   |                   |                   |                   |
       | 3. Registra CLABE |                   |                   |                   |
       | como beneficiario |                   |                   |                   |
       |------------------>|                   |                   |                   |
       |                   |                   |                   |                   |
       | 4. Transfiere     |                   |                   |                   |
       | $5,000 MXN        |                   |                   |                   |
       |------------------>|                   |                   |                   |
       |                   |                   |                   |                   |
       |                   | 5. SPEI procesa   |                   |                   |
       |                   | transferencia     |                   |                   |
       |                   | (5-30 min)        |                   |                   |
       |                   |------------------>|                   |                   |
       |                   |                   |                   |                   |
       |                   |                   | 6. Webhook:       |                   |
       |                   |                   | spei.incoming     |                   |
       |                   |                   |------------------>|                   |
       |                   |                   |                   |                   |
       |                   |                   |                   | 7. Validar CLABE  |
       |                   |                   |                   | en spei_references|
       |                   |                   |                   |                   |
       |                   |                   |                   | 8. Crear          |
       |                   |                   |                   | spei_deposit      |
       |                   |                   |                   | status: RECEIVED  |
       |                   |                   |                   |                   |
       |                   |                   |                   | 9. Obtener TC     |
       |                   |                   |                   | del dia           |
       |                   |                   |                   |                   |
       |                   |                   |                   | 10. Convertir     |
       |                   |                   |                   | $5000 MXN =       |
       |                   |                   |                   | $284.21 USD       |
       |                   |                   |                   |                   |
       |                   |                   |                   | 11. Acreditar     |
       |                   |                   |                   |------------------>|
       |                   |                   |                   |<------------------|
       |                   |                   |                   | wallet.balance    |
       |                   |                   |                   | += $284.21        |
       |                   |                   |                   |                   |
       |                   |                   |                   | 12. Update status |
       |                   |                   |                   | COMPLETED         |
       |                   |                   |                   |                   |
       |<------------------|-------------------|-------------------|                   |
       | Push: "Deposito   |                   |                   |                   |
       | recibido!         |                   |                   |                   |
       | +$284.21 USD"     |                   |                   |                   |
       |                   |                   |                   |                   |
       |<------------------|-------------------|-------------------|                   |
       | Email: Detalles   |                   |                   |                   |
       | del deposito      |                   |                   |                   |
       |                   |                   |                   |                   |

Reglas de Negocio

RN-001: Limites de Deposito SPEI

Limite Valor
Deposito minimo $100 MXN
Deposito maximo por transaccion $500,000 MXN
Deposito maximo diario $1,000,000 MXN
Sin limite mensual -

RN-002: Tipo de Cambio

  • Usar tipo de cambio FIX del Banco de Mexico
  • Actualizar tipo de cambio cada 15 minutos
  • Aplicar spread de 0.5% sobre tipo de cambio
  • Cachear tipo de cambio para consistencia intraday
  • Mostrar tipo de cambio antes de depositar

RN-003: Horarios SPEI

Horario Disponibilidad
Lunes-Viernes 6:00-17:30 Tiempo real (5-15 min)
Lunes-Viernes 17:30-20:00 Mismo dia (antes 20:00)
Sabados 6:00-14:00 Tiempo real
Domingos/Festivos Siguiente dia habil

RN-004: Validacion de Depositos

  • CLABE destino debe existir en spei_references
  • Monto debe estar dentro de limites
  • Referencia numerica no debe repetirse (idempotencia)
  • Depositos fuera de horario se procesan en siguiente ventana

RN-005: Reconciliacion

  • Depositos se reconcilian automaticamente por CLABE
  • No se requiere referencia especifica del usuario
  • Concepto de transferencia se guarda para auditoria
  • Reportes diarios a las 20:00 CST

Integracion con Stripe Mexico

Configuracion

// Crear cuenta SPEI reference
const speiReference = await stripe.customers.createSource(
  customerId,
  {
    type: 'clabe',
    clabe: {
      // Stripe genera automaticamente
    }
  }
);

// Resultado
{
  id: "src_xxx",
  type: "clabe",
  clabe: {
    clabe: "646180157000001234",
    bank_name: "STP",
    beneficiary_name: "STRIPE/TRADING PLATFORM"
  }
}

Webhook Handler

@Post('/webhooks/stripe/spei')
async handleSpeiWebhook(
  @Body() payload: StripeWebhookPayload,
  @Headers('stripe-signature') signature: string
) {
  // 1. Validar firma
  const event = stripe.webhooks.constructEvent(
    payload,
    signature,
    process.env.STRIPE_SPEI_WEBHOOK_SECRET
  );

  // 2. Procesar segun tipo de evento
  switch (event.type) {
    case 'source.chargeable':
      await this.processSpeiDeposit(event.data.object);
      break;
    case 'source.failed':
      await this.handleSpeiFailure(event.data.object);
      break;
  }

  return { received: true };
}

API Endpoints

Obtener CLABE

GET /api/v1/spei/clabe:
  description: Obtener CLABE virtual del usuario
  response:
    clabe: string
    bankName: string
    beneficiaryName: string
    limits:
      min: number
      max: number
      dailyMax: number
    exchangeRate:
      rate: number
      validUntil: string

Historial de Depositos SPEI

GET /api/v1/spei/deposits:
  description: Listar depositos SPEI del usuario
  query:
    page: number
    limit: number
    status: string
    dateFrom: string
    dateTo: string
  response:
    data:
      - id: string
        status: string
        montoMxn: number
        montoUsd: number
        tipoCambio: number
        fechaOperacion: string
        nombreOrdenante: string
    pagination:
      total: number
      page: number
      pages: number

Tipo de Cambio Actual

GET /api/v1/spei/exchange-rate:
  description: Obtener tipo de cambio MXN/USD actual
  response:
    rate: number
    spread: number
    effectiveRate: number
    validUntil: string
    source: string

Seguridad

Validacion de Webhooks

function validateStripeSpeiSignature(
  payload: string,
  signature: string,
  secret: string
): boolean {
  const expectedSig = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(`sha256=${expectedSig}`)
  );
}

Prevencion de Fraude

  • Monitorear depositos de misma CLABE origen (lavado)
  • Alerta si deposito > $100,000 MXN
  • Verificar RFC del ordenante vs usuario registrado
  • Bloquear cuenta si patron sospechoso

Idempotencia

  • Usar referenciaNumerica + fechaOperacion como clave unica
  • Ignorar webhooks duplicados
  • Registrar todos los intentos para auditoria

Manejo de Errores

Error Codigo Mensaje Usuario
CLABE no encontrada 404 Error interno. Contacta soporte.
Monto bajo limite 400 El monto minimo de deposito es $100 MXN
Monto sobre limite 400 El monto maximo por transferencia es $500,000 MXN
Limite diario excedido 400 Has excedido el limite diario de $1,000,000 MXN
Error de conversion 500 Error procesando tipo de cambio. Intenta mas tarde.
Proveedor no disponible 503 Sistema SPEI temporalmente no disponible

Webhooks Recibidos

Evento Accion
source.chargeable Crear spei_deposit, procesar conversion
source.failed Marcar como FAILED, notificar usuario
source.canceled Marcar como REJECTED

Configuracion Requerida

# Stripe Mexico
STRIPE_MX_SECRET_KEY=sk_xxx
STRIPE_SPEI_WEBHOOK_SECRET=whsec_xxx

# Conekta (alternativo)
CONEKTA_API_KEY=xxx
CONEKTA_WEBHOOK_SECRET=xxx

# Tipo de Cambio
EXCHANGE_RATE_API_URL=https://api.banxico.org.mx/SieAPIRest/service/v1/series/SF43718/datos/oportuno
EXCHANGE_RATE_BANXICO_TOKEN=xxx
EXCHANGE_RATE_CACHE_TTL_MINUTES=15
EXCHANGE_RATE_SPREAD=0.005

# Limites SPEI
SPEI_DEPOSIT_MIN_MXN=100
SPEI_DEPOSIT_MAX_MXN=500000
SPEI_DEPOSIT_MAX_DAILY_MXN=1000000

Metricas de Negocio

KPIs a Rastrear

  • Depositos SPEI/dia: Numero de depositos procesados
  • Volumen MXN/dia: Total depositado en MXN
  • Volumen USD/dia: Total convertido a USD
  • Ticket promedio: Monto promedio por deposito
  • Tiempo procesamiento: Promedio entre recepcion y acreditacion
  • Tasa de error: % de depositos fallidos/rechazados

Criterios de Aceptacion

  • Usuario obtiene CLABE unica de 18 digitos
  • CLABE se muestra con opcion de copiar
  • Depositos se detectan via webhook del agregador
  • Conversion MXN a USD aplica tipo de cambio correcto
  • Spread de 0.5% se aplica correctamente
  • Wallet se acredita en USD automaticamente
  • Push notification se envia al confirmar deposito
  • Email de confirmacion incluye todos los detalles
  • Depositos duplicados se manejan correctamente (idempotencia)
  • Limites de monto se validan correctamente
  • Historial de depositos SPEI es visible en UI
  • Tipo de cambio se actualiza cada 15 minutos

Especificacion Tecnica Relacionada

Historias de Usuario Relacionadas