Actualiza documentación de integraciones de pagos a estructura estándar de 11-13 secciones siguiendo template de INT-001. Cambios por integración: INT-004-mercadopago.md (+458 líneas): - Actualizado simco_version a 4.0.1 - Agregado: Rate Limits con retry strategy - Agregado: Manejo de Errores completo (8 códigos) - Agregado: Fallbacks y modo degradado - Mejorado: Multi-tenant con SQL schema - Agregado: Webhooks IPN con validación de firma - Agregado: Testing con tarjetas de prueba MX - Agregado: Monitoreo con métricas y logs INT-005-clip.md (+485 líneas): - Actualizado simco_version a 4.0.1 - Agregado: Rate Limits (100 req/min) - Agregado: Manejo de Errores (7 códigos) - Agregado: Fallbacks con cola Redis - Agregado: Multi-tenant con tenant_clip_config - Agregado: Webhooks con HMAC validation - Agregado: Testing con tarjetas Clip MX - Agregado: Monitoreo y Referencias INT-006-codi-banxico.md (+694 líneas): - Actualizado simco_version a 4.0.1 - Agregado: Rate Limits STP/Banxico - Agregado: Manejo de Errores CoDi/STP - Agregado: Fallbacks (QR alternativo, manual) - Agregado: Multi-tenant con CLABEs por tenant - Agregado: Webhooks STP con firma RSA-SHA256 - Agregado: Testing con CLABEs sandbox - Agregado: Monitoreo y normatividad mexicana Total: +1,573 líneas de documentación técnica. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
590 lines
18 KiB
Markdown
590 lines
18 KiB
Markdown
---
|
|
id: INT-005
|
|
type: Integration
|
|
title: "Terminal de pagos Clip"
|
|
provider: "Clip México"
|
|
status: Mock
|
|
integration_type: "Pagos con tarjeta"
|
|
created_at: 2026-01-10
|
|
updated_at: 2026-01-17
|
|
simco_version: "4.0.1"
|
|
tags:
|
|
- pagos
|
|
- tarjeta
|
|
- clip
|
|
- pos
|
|
- fintech
|
|
---
|
|
|
|
# INT-005: Terminal de pagos Clip
|
|
|
|
## Metadata
|
|
|
|
| Campo | Valor |
|
|
|-------|-------|
|
|
| **Codigo** | INT-005 |
|
|
| **Proveedor** | Clip México |
|
|
| **Tipo** | Pagos con tarjeta |
|
|
| **Estado** | Mock (pendiente de implementar) |
|
|
| **Multi-tenant** | Si |
|
|
| **Fecha planeada** | 2026-Q1 |
|
|
| **Owner** | Backend Team |
|
|
|
|
---
|
|
|
|
## 1. Descripcion
|
|
|
|
Integracion con el sistema de terminales punto de venta (TPV) de Clip Mexico para procesar pagos con tarjeta de credito y debito. Clip es una de las soluciones de pago mas populares en Mexico para pequenos comercios, permitiendo aceptar pagos con tarjeta sin necesidad de una cuenta bancaria empresarial tradicional.
|
|
|
|
**Casos de uso principales:**
|
|
- Cobro presencial con tarjeta de credito/debito en el changarro
|
|
- Generacion de links de pago para cobros a distancia
|
|
- Consulta de historial de transacciones y conciliacion
|
|
- Gestion de reembolsos y cancelaciones
|
|
- Reportes de ventas por periodo
|
|
|
|
---
|
|
|
|
## 2. Credenciales Requeridas
|
|
|
|
### Variables de Entorno
|
|
|
|
| Variable | Descripcion | Tipo | Obligatorio |
|
|
|----------|-------------|------|-------------|
|
|
| CLIP_API_KEY | Llave de API proporcionada por Clip | string | SI |
|
|
| CLIP_SECRET_KEY | Llave secreta para firmar requests | string | SI |
|
|
| CLIP_MERCHANT_ID | Identificador unico del comercio en Clip | string | SI |
|
|
| CLIP_WEBHOOK_SECRET | Secret para validar webhooks de Clip | string | SI |
|
|
| CLIP_ENVIRONMENT | Ambiente (sandbox/production) | string | SI |
|
|
|
|
### Ejemplo de .env
|
|
|
|
```env
|
|
# Terminal de pagos Clip
|
|
CLIP_API_KEY=clip_api_xxxxxxxxxxxxxxxx
|
|
CLIP_SECRET_KEY=clip_secret_xxxxxxxxxxxxxxxx
|
|
CLIP_MERCHANT_ID=mer_xxxxxxxxxxxxxxxx
|
|
CLIP_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxx
|
|
CLIP_ENVIRONMENT=sandbox
|
|
```
|
|
|
|
### Obtencion de Credenciales
|
|
|
|
1. Crear cuenta en [Clip Dashboard](https://dashboard.clip.mx/)
|
|
2. Acceder a la seccion de Desarrolladores
|
|
3. Generar API Key y Secret Key
|
|
4. Obtener Merchant ID de la configuracion de cuenta
|
|
5. Configurar Webhook URL y obtener Webhook Secret
|
|
|
|
---
|
|
|
|
## 3. Arquitectura
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ MiChangarrito │
|
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
|
|
│ │ Frontend │───▶│ API Server │───▶│ ClipService │ │
|
|
│ │ (Ventas) │ │ │ │ │ │
|
|
│ └──────────────┘ └──────────────┘ └────────┬─────────┘ │
|
|
└────────────────────────────────────────────────────┼────────────┘
|
|
│
|
|
▼
|
|
┌──────────────────┐
|
|
│ Clip API │
|
|
│ (México) │
|
|
│ │
|
|
│ - Pagos │
|
|
│ - Reembolsos │
|
|
│ - Consultas │
|
|
└──────────────────┘
|
|
```
|
|
|
|
### Flujo de Pago
|
|
|
|
1. Usuario selecciona "Pagar con tarjeta" en el punto de venta
|
|
2. Backend crea una sesion de pago en Clip API
|
|
3. Se genera un link/QR para completar el pago
|
|
4. Cliente realiza el pago con su tarjeta
|
|
5. Clip envia webhook de confirmacion
|
|
6. Backend actualiza estado de la venta
|
|
|
|
---
|
|
|
|
## 4. Endpoints
|
|
|
|
### Endpoints Consumidos (Clip API)
|
|
|
|
| Metodo | Endpoint | Descripcion |
|
|
|--------|----------|-------------|
|
|
| POST | `/v1/payments` | Crear un nuevo pago |
|
|
| GET | `/v1/payments/{id}` | Consultar estado de pago |
|
|
| POST | `/v1/payments/{id}/refund` | Procesar reembolso |
|
|
| GET | `/v1/transactions` | Listar transacciones |
|
|
| GET | `/v1/merchants/{id}/balance` | Consultar balance |
|
|
| POST | `/v1/payment-links` | Crear link de pago |
|
|
| GET | `/v1/payment-links/{id}` | Consultar link de pago |
|
|
|
|
### Endpoints Expuestos (MiChangarrito)
|
|
|
|
| Metodo | Endpoint | Descripcion |
|
|
|--------|----------|-------------|
|
|
| POST | `/api/v1/payments/clip/create` | Iniciar pago con Clip |
|
|
| GET | `/api/v1/payments/clip/{id}` | Consultar pago |
|
|
| POST | `/api/v1/payments/clip/{id}/refund` | Solicitar reembolso |
|
|
| POST | `/api/v1/payments/clip/payment-link` | Crear link de pago |
|
|
| POST | `/api/v1/webhooks/clip` | Recibir notificaciones de Clip |
|
|
|
|
---
|
|
|
|
## 5. Rate Limits
|
|
|
|
| Limite | Valor | Periodo | Accion si excede |
|
|
|--------|-------|---------|------------------|
|
|
| Requests API | 100 | por minuto | 429 + Retry-After |
|
|
| Crear pagos | 60 | por minuto | 429 + backoff |
|
|
| Consultas | 200 | por minuto | 429 + Retry-After |
|
|
| Webhooks | Sin limite | - | N/A |
|
|
|
|
### Estrategia de Retry
|
|
|
|
```typescript
|
|
const RETRY_DELAYS = [1000, 2000, 4000, 8000];
|
|
|
|
async function executeWithRetry<T>(
|
|
operation: () => Promise<T>,
|
|
maxRetries = 4
|
|
): Promise<T> {
|
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
try {
|
|
return await operation();
|
|
} catch (error) {
|
|
if (error.response?.status === 429 && attempt < maxRetries - 1) {
|
|
const retryAfter = error.response.headers['retry-after'];
|
|
const delay = retryAfter
|
|
? parseInt(retryAfter) * 1000
|
|
: RETRY_DELAYS[attempt];
|
|
await sleep(delay);
|
|
continue;
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
throw new Error('Max retries exceeded');
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Manejo de Errores
|
|
|
|
### Codigos de Error
|
|
|
|
| Codigo | Descripcion | Accion Recomendada | Retry |
|
|
|--------|-------------|-------------------|-------|
|
|
| 400 | Request invalido | Validar parametros enviados | NO |
|
|
| 401 | Credenciales invalidas | Verificar API Key y Secret | NO |
|
|
| 402 | Pago rechazado | Informar al usuario, ofrecer alternativa | NO |
|
|
| 403 | Operacion no permitida | Verificar permisos del merchant | NO |
|
|
| 404 | Recurso no encontrado | Verificar ID de pago/transaccion | NO |
|
|
| 429 | Rate limit excedido | Esperar y reintentar con backoff | SI |
|
|
| 500 | Error interno de Clip | Reintentar con backoff exponencial | SI |
|
|
|
|
### Ejemplo de Manejo
|
|
|
|
```typescript
|
|
import { Injectable, Logger, BadRequestException } from '@nestjs/common';
|
|
|
|
@Injectable()
|
|
export class ClipService {
|
|
private readonly logger = new Logger(ClipService.name);
|
|
|
|
async createPayment(params: CreatePaymentDto, tenantId: string): Promise<ClipPayment> {
|
|
try {
|
|
const response = await this.clipClient.post('/v1/payments', params);
|
|
|
|
this.logger.log('Clip payment created', {
|
|
service: 'clip',
|
|
operation: 'createPayment',
|
|
paymentId: response.data.id,
|
|
amount: params.amount,
|
|
tenantId,
|
|
});
|
|
|
|
return response.data;
|
|
} catch (error) {
|
|
const clipError = error.response?.data;
|
|
|
|
this.logger.error('Clip payment failed', {
|
|
service: 'clip',
|
|
operation: 'createPayment',
|
|
code: clipError?.code || error.response?.status,
|
|
message: clipError?.message || error.message,
|
|
tenantId,
|
|
});
|
|
|
|
switch (error.response?.status) {
|
|
case 400:
|
|
throw new BadRequestException(clipError?.message || 'Parametros de pago invalidos');
|
|
case 401:
|
|
throw new Error('Credenciales de Clip invalidas');
|
|
case 402:
|
|
throw new BadRequestException('Pago rechazado: ' + clipError?.decline_reason);
|
|
case 429:
|
|
// Encolar para reintento
|
|
await this.queue.add('clip-payment-retry', { params, tenantId });
|
|
throw new Error('Servicio ocupado, reintentando...');
|
|
default:
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Fallbacks
|
|
|
|
### Estrategia de Fallback
|
|
|
|
| Escenario | Fallback | Tiempo maximo |
|
|
|-----------|----------|---------------|
|
|
| Clip API caida | Encolar pago para reintento | 24 horas |
|
|
| Rate limited | Throttle + cola prioritaria | 1 hora |
|
|
| Pago rechazado | Ofrecer link de pago alternativo | Inmediato |
|
|
| Timeout | Verificar estado y reintentar | 3 intentos |
|
|
|
|
### Modo Degradado
|
|
|
|
Si Clip no esta disponible:
|
|
- Pagos presenciales se encolan en Redis para reintento
|
|
- Usuario puede optar por efectivo y registrar manualmente
|
|
- Links de pago existentes siguen funcionando
|
|
- Notificacion a admin sobre estado del servicio
|
|
|
|
```typescript
|
|
async createPaymentWithFallback(
|
|
params: CreatePaymentDto,
|
|
tenantId: string
|
|
): Promise<PaymentResult> {
|
|
try {
|
|
return await this.createPayment(params, tenantId);
|
|
} catch (error) {
|
|
if (this.isClipUnavailable(error)) {
|
|
// Encolar para reintento posterior
|
|
const jobId = await this.queue.add('clip-payment-pending', {
|
|
params,
|
|
tenantId,
|
|
createdAt: new Date().toISOString(),
|
|
});
|
|
|
|
return {
|
|
status: 'pending_retry',
|
|
jobId,
|
|
message: 'Pago encolado, se procesara cuando Clip este disponible',
|
|
};
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Multi-tenant
|
|
|
|
### Modelo de Credenciales
|
|
|
|
- [x] **Por Tenant:** Cada tenant puede configurar sus propias credenciales Clip
|
|
- [x] **Global con fallback:** Credenciales compartidas si tenant no tiene propias
|
|
|
|
### Almacenamiento
|
|
|
|
```sql
|
|
-- En schema payments
|
|
CREATE TABLE payments.tenant_clip_config (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id UUID REFERENCES auth.tenants(id) NOT NULL,
|
|
api_key TEXT NOT NULL, -- Encriptado con AES-256
|
|
secret_key TEXT NOT NULL, -- Encriptado con AES-256
|
|
merchant_id VARCHAR(50) NOT NULL,
|
|
webhook_secret TEXT, -- Encriptado
|
|
environment VARCHAR(20) DEFAULT 'sandbox',
|
|
commission_rate DECIMAL(5,4) DEFAULT 0.0360, -- 3.6% default
|
|
is_active BOOLEAN DEFAULT true,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
UNIQUE(tenant_id)
|
|
);
|
|
|
|
-- Indice para busqueda rapida
|
|
CREATE INDEX idx_tenant_clip_config_tenant ON payments.tenant_clip_config(tenant_id);
|
|
```
|
|
|
|
### Contexto en Llamadas
|
|
|
|
```typescript
|
|
@Injectable()
|
|
export class ClipService {
|
|
async getClientForTenant(tenantId: string): Promise<ClipClient> {
|
|
// Buscar configuracion del tenant
|
|
const config = await this.configRepo.findOne({ where: { tenantId } });
|
|
|
|
if (config?.is_active) {
|
|
return new ClipClient({
|
|
apiKey: this.decrypt(config.api_key),
|
|
secretKey: this.decrypt(config.secret_key),
|
|
merchantId: config.merchant_id,
|
|
environment: config.environment,
|
|
});
|
|
}
|
|
|
|
// Fallback a credenciales globales
|
|
return new ClipClient({
|
|
apiKey: this.configService.get('CLIP_API_KEY'),
|
|
secretKey: this.configService.get('CLIP_SECRET_KEY'),
|
|
merchantId: this.configService.get('CLIP_MERCHANT_ID'),
|
|
environment: this.configService.get('CLIP_ENVIRONMENT'),
|
|
});
|
|
}
|
|
|
|
async createPaymentForTenant(
|
|
tenantId: string,
|
|
params: CreatePaymentDto
|
|
): Promise<ClipPayment> {
|
|
const client = await this.getClientForTenant(tenantId);
|
|
return client.payments.create(params);
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 9. Webhooks
|
|
|
|
### Endpoints Registrados
|
|
|
|
| Evento | Endpoint Local | Descripcion |
|
|
|--------|----------------|-------------|
|
|
| `payment.created` | `/webhooks/clip` | Pago creado |
|
|
| `payment.approved` | `/webhooks/clip` | Pago aprobado |
|
|
| `payment.declined` | `/webhooks/clip` | Pago rechazado |
|
|
| `payment.refunded` | `/webhooks/clip` | Pago reembolsado |
|
|
| `payment_link.paid` | `/webhooks/clip` | Link de pago completado |
|
|
|
|
### Validacion HMAC de Firma
|
|
|
|
```typescript
|
|
import * as crypto from 'crypto';
|
|
|
|
function verifyClipWebhookSignature(
|
|
payload: string,
|
|
signature: string,
|
|
webhookSecret: string
|
|
): boolean {
|
|
const expectedSignature = crypto
|
|
.createHmac('sha256', webhookSecret)
|
|
.update(payload, 'utf8')
|
|
.digest('hex');
|
|
|
|
// Comparacion segura contra timing attacks
|
|
return crypto.timingSafeEqual(
|
|
Buffer.from(signature),
|
|
Buffer.from(expectedSignature)
|
|
);
|
|
}
|
|
|
|
// Controller
|
|
@Post('/webhooks/clip')
|
|
async handleClipWebhook(
|
|
@Body() body: any,
|
|
@Headers('X-Clip-Signature') signature: string,
|
|
@Req() request: Request
|
|
): Promise<{ received: boolean }> {
|
|
const rawBody = (request as any).rawBody;
|
|
|
|
// Determinar webhook secret (puede ser por tenant)
|
|
const webhookSecret = await this.getWebhookSecret(body.merchant_id);
|
|
|
|
if (!verifyClipWebhookSignature(rawBody, signature, webhookSecret)) {
|
|
throw new UnauthorizedException('Invalid webhook signature');
|
|
}
|
|
|
|
await this.processWebhookEvent(body);
|
|
return { received: true };
|
|
}
|
|
```
|
|
|
|
### Configuracion en Clip Dashboard
|
|
|
|
1. Acceder a Clip Dashboard > Desarrolladores > Webhooks
|
|
2. Agregar endpoint: `https://api.michangarrito.com/webhooks/clip`
|
|
3. Seleccionar eventos: `payment.*`, `payment_link.*`
|
|
4. Guardar y copiar el Webhook Secret
|
|
5. Configurar en variable de entorno `CLIP_WEBHOOK_SECRET`
|
|
|
|
---
|
|
|
|
## 10. Testing
|
|
|
|
### Modo Sandbox
|
|
|
|
| Ambiente | Credenciales | Comportamiento |
|
|
|----------|--------------|----------------|
|
|
| Sandbox | `clip_api_test_*` | Pagos simulados, sin cargos reales |
|
|
| Production | `clip_api_live_*` | Pagos reales con tarjetas |
|
|
|
|
### Tarjetas de Prueba Clip
|
|
|
|
```
|
|
# Pago exitoso
|
|
4242 4242 4242 4242 Exp: 12/28 CVV: 123
|
|
|
|
# Pago rechazado - Fondos insuficientes
|
|
4000 0000 0000 0002 Exp: 12/28 CVV: 123
|
|
|
|
# Pago rechazado - Tarjeta robada
|
|
4000 0000 0000 0069 Exp: 12/28 CVV: 123
|
|
|
|
# Requiere autenticacion 3D Secure
|
|
4000 0027 6000 3184 Exp: 12/28 CVV: 123
|
|
```
|
|
|
|
### Comandos de Test
|
|
|
|
```bash
|
|
# Test crear pago
|
|
curl -X POST https://api-sandbox.clip.mx/v1/payments \
|
|
-H "Authorization: Bearer ${CLIP_API_KEY}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"amount": 150.00,
|
|
"currency": "MXN",
|
|
"description": "Venta de prueba MiChangarrito",
|
|
"reference": "test-order-001"
|
|
}'
|
|
|
|
# Test consultar pago
|
|
curl -X GET "https://api-sandbox.clip.mx/v1/payments/${PAYMENT_ID}" \
|
|
-H "Authorization: Bearer ${CLIP_API_KEY}"
|
|
|
|
# Test crear link de pago
|
|
curl -X POST https://api-sandbox.clip.mx/v1/payment-links \
|
|
-H "Authorization: Bearer ${CLIP_API_KEY}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"amount": 299.00,
|
|
"currency": "MXN",
|
|
"description": "Pedido a domicilio",
|
|
"expires_at": "2026-01-20T23:59:59Z"
|
|
}'
|
|
|
|
# Test webhook local (simular evento)
|
|
curl -X POST http://localhost:3143/webhooks/clip \
|
|
-H "Content-Type: application/json" \
|
|
-H "X-Clip-Signature: $(echo -n '{"event":"payment.approved","data":{"id":"pay_123"}}' | openssl dgst -sha256 -hmac ${CLIP_WEBHOOK_SECRET})" \
|
|
-d '{"event":"payment.approved","data":{"id":"pay_123","amount":150.00,"status":"approved"}}'
|
|
```
|
|
|
|
---
|
|
|
|
## 11. Monitoreo
|
|
|
|
### Metricas a Monitorear
|
|
|
|
| Metrica | Descripcion | Alerta |
|
|
|---------|-------------|--------|
|
|
| Latencia API | Tiempo de respuesta Clip API | > 5s |
|
|
| Error Rate | % de requests fallidos | > 5% |
|
|
| Decline Rate | % de pagos rechazados | > 15% |
|
|
| Webhook Delay | Tiempo entre pago y webhook | > 30s |
|
|
| Success Rate | % de pagos exitosos | < 85% |
|
|
| Daily Volume | Volumen diario en MXN | Anomalia |
|
|
|
|
### Logs Estructurados
|
|
|
|
```typescript
|
|
// Pago exitoso
|
|
this.logger.info('Clip payment successful', {
|
|
service: 'clip',
|
|
operation: 'createPayment',
|
|
tenantId: context.tenantId,
|
|
paymentId: result.id,
|
|
amount: params.amount,
|
|
currency: 'MXN',
|
|
duration: durationMs,
|
|
});
|
|
|
|
// Pago rechazado
|
|
this.logger.warn('Clip payment declined', {
|
|
service: 'clip',
|
|
operation: 'createPayment',
|
|
tenantId: context.tenantId,
|
|
declineCode: error.decline_code,
|
|
declineReason: error.decline_reason,
|
|
amount: params.amount,
|
|
});
|
|
|
|
// Webhook recibido
|
|
this.logger.info('Clip webhook received', {
|
|
service: 'clip',
|
|
operation: 'webhook',
|
|
event: payload.event,
|
|
paymentId: payload.data.id,
|
|
merchantId: payload.merchant_id,
|
|
});
|
|
```
|
|
|
|
### Dashboard Recomendado
|
|
|
|
Configurar en Grafana/DataDog:
|
|
- Grafica de volumen de pagos por hora
|
|
- Grafica de tasa de exito/rechazo
|
|
- Alertas de latencia y errores
|
|
- Resumen de comisiones acumuladas
|
|
|
|
---
|
|
|
|
## 12. Referencias
|
|
|
|
### Documentacion Oficial Clip
|
|
- [Clip API Documentation](https://developer.clip.mx/docs)
|
|
- [Clip Dashboard](https://dashboard.clip.mx/)
|
|
- [Webhooks Reference](https://developer.clip.mx/docs/webhooks)
|
|
- [Tarjetas de Prueba](https://developer.clip.mx/docs/testing)
|
|
|
|
### Informacion de Clip Mexico
|
|
- Comision estandar: 3.6% + IVA por transaccion
|
|
- Depositos: 24-48 horas habiles
|
|
- Soporte: soporte@clip.mx
|
|
- Telefono: 55 4162 5252
|
|
|
|
### Modulos Relacionados
|
|
- [Payments Module](../../apps/backend/src/modules/payments/)
|
|
- [Sales Module](../../apps/backend/src/modules/sales/)
|
|
- [Arquitectura Multi-Tenant](../90-transversal/ARQUITECTURA-MULTI-TENANT-INTEGRACIONES.md)
|
|
|
|
### Integraciones Relacionadas
|
|
- [INT-002: Stripe](./INT-002-stripe.md) - Suscripciones de MiChangarrito
|
|
- [INT-004: MercadoPago](./INT-004-mercadopago.md) - Alternativa de pagos
|
|
- [INT-006: CoDi Banxico](./INT-006-codi-banxico.md) - Pagos QR bancarios
|
|
|
|
---
|
|
|
|
## 13. Notas de Implementacion
|
|
|
|
- La integracion requiere cuenta de desarrollador en Clip Portal
|
|
- Clip cobra comision del 3.6% + IVA por transaccion
|
|
- Los fondos se depositan en 24-48 horas habiles
|
|
- Implementar idempotency keys para evitar cobros duplicados
|
|
- Validar firma HMAC en todos los webhooks recibidos
|
|
- Manejar los estados de pago: pending, approved, declined, refunded
|
|
- Considerar limites de rate limiting de la API (100 req/min)
|
|
- En ambiente sandbox usar tarjetas de prueba proporcionadas por Clip
|
|
|
|
---
|
|
|
|
**Ultima actualizacion:** 2026-01-17
|
|
**Autor:** Backend Team
|