diff --git a/docs/02-definicion-modulos/OQI-005-payments-stripe/DEVELOPER-GUIDELINES.md b/docs/02-definicion-modulos/OQI-005-payments-stripe/DEVELOPER-GUIDELINES.md
new file mode 100644
index 0000000..bb12325
--- /dev/null
+++ b/docs/02-definicion-modulos/OQI-005-payments-stripe/DEVELOPER-GUIDELINES.md
@@ -0,0 +1,997 @@
+# Developer Guidelines: Payment System
+
+**Epic:** OQI-005 - Payments & Stripe
+**Blocker:** BLOCKER-002 (ST4.2.5)
+**Version:** 1.0.0
+**Last Updated:** 2026-01-26
+**Status:** ✅ Complete
+
+---
+
+## Table of Contents
+
+1. [Overview](#overview)
+2. [PCI-DSS Compliance Rules](#pci-dss-compliance-rules)
+3. [Backend Development](#backend-development)
+4. [Frontend Development](#frontend-development)
+5. [Testing Guidelines](#testing-guidelines)
+6. [Common Pitfalls](#common-pitfalls)
+7. [Code Review Checklist](#code-review-checklist)
+8. [Deployment Checklist](#deployment-checklist)
+9. [Troubleshooting](#troubleshooting)
+10. [Examples & Templates](#examples--templates)
+
+---
+
+## Overview
+
+### Architecture Summary
+
+```
+Frontend (React) → Backend (Express.js) → Stripe API
+ ↓ ↓ ↓
+ CardElement Payment Intent Processing
+ (Stripe.js) (server-side) (Stripe servers)
+```
+
+**Key Principle:** ⚠️ **Card data NEVER touches our servers**
+
+### Technology Stack
+
+- **Backend:** Express.js, TypeScript, Stripe Node.js SDK
+- **Frontend:** React, TypeScript, @stripe/stripe-js, @stripe/react-stripe-js
+- **Database:** PostgreSQL (NO card data stored)
+- **Payment Processor:** Stripe (Level 1 PCI-DSS certified)
+
+### Compliance Level
+
+**PCI-DSS SAQ-A** (Self-Assessment Questionnaire A)
+- Simplest compliance path (22 requirements vs 300+)
+- Achieved by delegating ALL card processing to Stripe
+- **Required:** NO card data on our systems
+
+---
+
+## PCI-DSS Compliance Rules
+
+### ✅ ALLOWED
+
+**Backend:**
+```typescript
+// ✅ Create Payment Intent (server-side)
+const paymentIntent = await stripe.paymentIntents.create({
+ amount: 10000,
+ currency: 'usd',
+ metadata: { userId, transactionId },
+});
+
+// ✅ Store safe identifiers
+await db.query(
+ 'INSERT INTO transactions (payment_intent_id, amount) VALUES ($1, $2)',
+ [paymentIntent.id, 100] // ← Safe: token ID, not card data
+);
+
+// ✅ Store card metadata (last4, brand)
+await db.query(
+ 'UPDATE payment_methods SET card_last4 = $1, card_brand = $2',
+ ['4242', 'visa'] // ← Safe: not full PAN
+);
+```
+
+**Frontend:**
+```typescript
+// ✅ Use Stripe Elements (hosted iframe)
+import { CardElement } from '@stripe/react-stripe-js';
+
+
+
+// ✅ Confirm payment with Stripe
+const { error, paymentIntent } = await stripe.confirmCardPayment(
+ clientSecret,
+ { payment_method: { card: cardElement } } // ← Card data goes to Stripe
+);
+```
+
+### ❌ PROHIBITED
+
+**NEVER DO THIS:**
+
+```typescript
+// ❌ PROHIBITED: Accept card data in backend
+export async function createPayment(req, res) {
+ const { cardNumber, cvv, expiryDate } = req.body; // ← VIOLATION!
+ // ... DO NOT DO THIS
+}
+
+// ❌ PROHIBITED: Store card data in database
+await db.query(
+ 'INSERT INTO payment_methods (card_number, cvv) VALUES ($1, $2)',
+ ['4242424242424242', '123'] // ← SEVERE VIOLATION!
+);
+
+// ❌ PROHIBITED: Create native card input
+
+
+// ❌ PROHIBITED: Store card data in React state
+const [cardNumber, setCardNumber] = useState(''); // ← VIOLATION!
+
+// ❌ PROHIBITED: Log sensitive data
+console.log('Card:', cardNumber, cvv); // ← VIOLATION!
+```
+
+**Consequences:**
+- 💰 **Fines:** Up to $500,000 per incident
+- 🚫 **Loss of payment processing:** Stripe account terminated
+- ⚖️ **Legal liability:** GDPR violations
+- 📰 **Reputation damage:** Customer trust lost
+
+### PCI-DSS Quick Reference
+
+| Action | Allowed | Example |
+|--------|---------|---------|
+| Store full PAN (card number) | ❌ NO | 4242424242424242 |
+| Store CVV/CVC | ❌ NO | 123 |
+| Store expiry date | ❌ NO | 12/25 |
+| Store PIN | ❌ NO | 1234 |
+| Store last 4 digits | ✅ YES | 4242 |
+| Store card brand | ✅ YES | visa |
+| Store Stripe token | ✅ YES | pm_xxx, pi_xxx |
+| Store customer name | ✅ YES | John Doe |
+
+**Rule of Thumb:** If it can be used to make a fraudulent charge, **DON'T STORE IT**.
+
+---
+
+## Backend Development
+
+### File Structure
+
+```
+src/modules/payments/
+├── controllers/
+│ └── payments.controller.ts # REST API endpoints
+├── services/
+│ ├── stripe.service.ts # Stripe API wrapper
+│ ├── wallet.service.ts # Wallet management
+│ └── subscription.service.ts # Subscription logic
+├── types/
+│ └── payments.types.ts # TypeScript types
+└── payments.routes.ts # Express routes
+```
+
+### Creating a New Payment Endpoint
+
+**Step 1: Define Route**
+
+```typescript
+// payments.routes.ts
+router.post(
+ '/wallet/deposit',
+ requireAuth, // ← Always require auth
+ createDeposit // ← Controller function
+);
+```
+
+**Step 2: Create Controller**
+
+```typescript
+// controllers/payments.controller.ts
+export async function createDeposit(req, res, next) {
+ try {
+ const authReq = req as AuthenticatedRequest;
+ const { amount, currency } = req.body;
+
+ // ✅ Validation
+ if (!amount || amount <= 0) {
+ res.status(400).json({ error: 'Invalid amount' });
+ return;
+ }
+
+ // ❌ Block sensitive data (CRITICAL!)
+ const sensitiveFields = ['cardNumber', 'cvv', 'pan', 'expiryDate'];
+ if (sensitiveFields.some(field => req.body[field])) {
+ logger.warn('Sensitive data blocked', { userId: authReq.user.id });
+ res.status(400).json({ error: 'Card data not allowed' });
+ return;
+ }
+
+ // ✅ Call service
+ const result = await stripeService.createPaymentIntent({
+ userId: authReq.user.id,
+ amount,
+ currency,
+ });
+
+ res.json({ success: true, data: result });
+ } catch (error) {
+ next(error); // ← Always use error middleware
+ }
+}
+```
+
+**Step 3: Implement Service**
+
+```typescript
+// services/stripe.service.ts
+export class StripeService {
+ async createPaymentIntent(params: {
+ userId: string;
+ amount: number;
+ currency: string;
+ }): Promise<{ clientSecret: string; paymentIntentId: string }> {
+ // ✅ Create Payment Intent (server-side)
+ const paymentIntent = await this.stripe.paymentIntents.create({
+ amount: Math.round(params.amount * 100), // Convert to cents
+ currency: params.currency.toLowerCase(),
+ metadata: {
+ userId: params.userId,
+ type: 'wallet_deposit',
+ },
+ });
+
+ // ✅ Store transaction in database (safe data only)
+ await db.query(
+ `INSERT INTO payments.transactions (
+ user_id, amount, currency, status, payment_intent_id
+ ) VALUES ($1, $2, $3, $4, $5)`,
+ [params.userId, params.amount, params.currency, 'pending', paymentIntent.id]
+ );
+
+ // ✅ Return client secret (frontend will use this)
+ return {
+ clientSecret: paymentIntent.client_secret!,
+ paymentIntentId: paymentIntent.id,
+ };
+ }
+}
+```
+
+### Webhook Implementation
+
+**Critical:** Webhooks MUST verify Stripe signature
+
+```typescript
+// controllers/payments.controller.ts
+export async function handleStripeWebhook(req, res, next) {
+ const signature = req.headers['stripe-signature'] as string;
+ const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET!;
+
+ try {
+ // ✅ CRITICAL: Verify signature (prevents spoofing)
+ const event = stripe.webhooks.constructEvent(
+ req.body, // ← Must be raw body (not JSON parsed)
+ signature,
+ webhookSecret
+ );
+
+ logger.info('Webhook received', {
+ type: event.type,
+ id: event.id,
+ });
+
+ // Handle event types
+ switch (event.type) {
+ case 'payment_intent.succeeded':
+ await handlePaymentSucceeded(event.data.object);
+ break;
+
+ case 'payment_intent.payment_failed':
+ await handlePaymentFailed(event.data.object);
+ break;
+
+ case 'customer.subscription.created':
+ await handleSubscriptionCreated(event.data.object);
+ break;
+
+ default:
+ logger.warn('Unhandled webhook event', { type: event.type });
+ }
+
+ res.json({ received: true });
+ } catch (err) {
+ // ❌ Invalid signature - REJECT
+ logger.error('Webhook verification failed', { error: err });
+ res.status(400).json({ error: 'Invalid signature' });
+ }
+}
+```
+
+**Important:** Webhook endpoint must use raw body parser:
+
+```typescript
+// app.ts
+import { raw } from 'express';
+
+app.post(
+ '/api/v1/payments/webhook',
+ raw({ type: 'application/json' }), // ← Raw body for signature verification
+ handleStripeWebhook
+);
+```
+
+### Database Schema Guidelines
+
+**✅ ALLOWED columns:**
+```sql
+CREATE TABLE payments.transactions (
+ id UUID PRIMARY KEY,
+ user_id UUID NOT NULL,
+ amount DECIMAL(10,2),
+ currency VARCHAR(3),
+ status VARCHAR(50),
+ payment_intent_id VARCHAR(255), -- ✅ Stripe token
+ stripe_customer_id VARCHAR(255), -- ✅ Stripe ID
+ created_at TIMESTAMPTZ
+);
+```
+
+**❌ PROHIBITED columns:**
+```sql
+-- ❌ NEVER create these columns!
+card_number VARCHAR(16) -- PAN
+cvv VARCHAR(4) -- Security code
+expiry_date DATE -- Expiration
+card_holder_name VARCHAR(100) -- Sensitive
+pin VARCHAR(4) -- PIN
+```
+
+---
+
+## Frontend Development
+
+### Stripe Elements Setup
+
+**Step 1: Wrap App with Stripe Provider**
+
+```typescript
+// App.tsx
+import { Elements } from '@stripe/react-stripe-js';
+import { loadStripe } from '@stripe/stripe-js';
+
+const stripePromise = loadStripe(process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY!);
+
+function App() {
+ return (
+
+
+
+ );
+}
+```
+
+**Step 2: Create Payment Form**
+
+```typescript
+// DepositForm.tsx
+import { CardElement, useStripe, useElements } from '@stripe/react-stripe-js';
+
+function DepositForm() {
+ const stripe = useStripe();
+ const elements = useElements();
+ const [amount, setAmount] = useState(100);
+ const [processing, setProcessing] = useState(false);
+ const [error, setError] = useState(null);
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+
+ if (!stripe || !elements) {
+ return; // Stripe not loaded yet
+ }
+
+ setProcessing(true);
+ setError(null);
+
+ try {
+ // Step 1: Backend creates Payment Intent (NO card data sent)
+ const response = await apiClient.post('/api/v1/payments/wallet/deposit', {
+ amount, // ✅ Safe
+ currency: 'USD', // ✅ Safe
+ // ❌ NO cardNumber, cvv, expiryDate
+ });
+
+ const { clientSecret } = response.data.data;
+
+ // Step 2: Confirm payment with Stripe (card data goes to Stripe)
+ const cardElement = elements.getElement(CardElement);
+
+ const { error, paymentIntent } = await stripe.confirmCardPayment(
+ clientSecret,
+ {
+ payment_method: {
+ card: cardElement!, // ← Stripe iframe reference
+ },
+ }
+ );
+
+ if (error) {
+ setError(error.message || 'Payment failed');
+ } else if (paymentIntent.status === 'succeeded') {
+ // ✅ Success! (Backend webhook will update database)
+ onSuccess();
+ }
+ } catch (err) {
+ setError(err.message || 'An error occurred');
+ } finally {
+ setProcessing(false);
+ }
+ };
+
+ return (
+
+ );
+}
+```
+
+### Checkout Session Flow (Stripe Hosted)
+
+For subscription payments, use Stripe Checkout (hosted page):
+
+```typescript
+// SubscriptionButton.tsx
+async function handleSubscribe() {
+ // Backend creates Checkout Session
+ const response = await apiClient.post('/api/v1/payments/checkout', {
+ planId: 'plan_basic',
+ billingCycle: 'monthly',
+ successUrl: `${window.location.origin}/success`,
+ cancelUrl: `${window.location.origin}/cancel`,
+ });
+
+ const { url } = response.data.data;
+
+ // ✅ Redirect to Stripe hosted page
+ window.location.href = url; // ← User enters card on checkout.stripe.com
+}
+```
+
+### Error Handling
+
+```typescript
+// Handle Stripe errors
+const { error, paymentIntent } = await stripe.confirmCardPayment(clientSecret, {...});
+
+if (error) {
+ // Stripe validation errors
+ switch (error.type) {
+ case 'card_error':
+ // Card was declined, invalid number, etc.
+ setError(error.message);
+ break;
+
+ case 'validation_error':
+ // Invalid parameters sent to Stripe
+ setError('Please check your input');
+ break;
+
+ case 'api_error':
+ // Stripe API issue
+ setError('Payment service unavailable');
+ break;
+
+ default:
+ setError('An unexpected error occurred');
+ }
+}
+```
+
+---
+
+## Testing Guidelines
+
+### Backend Tests
+
+**Unit Tests:**
+```typescript
+// stripe.service.test.ts
+describe('StripeService', () => {
+ it('should create Payment Intent', async () => {
+ const mockStripe = {
+ paymentIntents: {
+ create: jest.fn().mockResolvedValue({
+ id: 'pi_test_123',
+ client_secret: 'pi_test_123_secret_456',
+ }),
+ },
+ };
+
+ const service = new StripeService(mockStripe);
+
+ const result = await service.createPaymentIntent({
+ userId: 'user_123',
+ amount: 100,
+ currency: 'usd',
+ });
+
+ expect(result.clientSecret).toBe('pi_test_123_secret_456');
+ expect(mockStripe.paymentIntents.create).toHaveBeenCalledWith({
+ amount: 10000,
+ currency: 'usd',
+ metadata: expect.objectContaining({ userId: 'user_123' }),
+ });
+ });
+});
+```
+
+**E2E Tests (PCI-DSS Compliance):**
+```typescript
+// payments-pci-dss.test.ts
+describe('PCI-DSS Compliance', () => {
+ it('should reject request with card data', async () => {
+ const response = await request(app)
+ .post('/api/v1/payments/wallet/deposit')
+ .set('Authorization', `Bearer ${token}`)
+ .send({
+ amount: 100,
+ cardNumber: '4242424242424242', // ← Attempt to send card data
+ })
+ .expect(400);
+
+ expect(response.body.error).toContain('Card data not allowed');
+ });
+});
+```
+
+### Frontend Tests
+
+**Component Tests:**
+```typescript
+// DepositForm.test.tsx
+import { render, screen, fireEvent } from '@testing-library/react';
+import { Elements } from '@stripe/react-stripe-js';
+
+describe('DepositForm', () => {
+ it('should render Stripe CardElement', () => {
+ render(
+
+
+
+ );
+
+ // ✅ Stripe CardElement rendered
+ expect(screen.getByTestId('stripe-card-element')).toBeInTheDocument();
+
+ // ❌ NO native card inputs
+ expect(screen.queryByPlaceholderText(/card number/i)).not.toBeInTheDocument();
+ });
+
+ it('should NOT store card data in state', () => {
+ const { container } = render(
+
+
+
+ );
+
+ const html = container.innerHTML;
+
+ // ❌ NO card data in DOM
+ expect(html).not.toContain('cardNumber');
+ expect(html).not.toContain('cvv');
+ });
+});
+```
+
+---
+
+## Common Pitfalls
+
+### Pitfall 1: Accepting Card Data in Backend
+
+**❌ WRONG:**
+```typescript
+export async function createPayment(req, res) {
+ const { cardNumber, cvv } = req.body; // ← VIOLATION!
+ // ...
+}
+```
+
+**✅ CORRECT:**
+```typescript
+export async function createPayment(req, res) {
+ const { amount, currency } = req.body;
+
+ // Block sensitive data
+ if (req.body.cardNumber || req.body.cvv) {
+ return res.status(400).json({ error: 'Card data not allowed' });
+ }
+
+ // Create Payment Intent (safe)
+ const paymentIntent = await stripe.paymentIntents.create({ amount, currency });
+ res.json({ clientSecret: paymentIntent.client_secret });
+}
+```
+
+### Pitfall 2: Storing Full PAN in Database
+
+**❌ WRONG:**
+```sql
+CREATE TABLE payment_methods (
+ card_number VARCHAR(16) -- ← SEVERE VIOLATION!
+);
+```
+
+**✅ CORRECT:**
+```sql
+CREATE TABLE payment_methods (
+ stripe_payment_method_id VARCHAR(255), -- ✅ Token
+ card_last4 VARCHAR(4), -- ✅ Last 4 digits
+ card_brand VARCHAR(50) -- ✅ Metadata
+);
+```
+
+### Pitfall 3: Native Card Inputs
+
+**❌ WRONG:**
+```tsx
+ {/* VIOLATION! */}
+```
+
+**✅ CORRECT:**
+```tsx
+import { CardElement } from '@stripe/react-stripe-js';
+
+ {/* Stripe iframe */}
+```
+
+### Pitfall 4: Not Verifying Webhook Signatures
+
+**❌ WRONG:**
+```typescript
+export async function handleWebhook(req, res) {
+ const event = req.body; // ← NO VERIFICATION! Insecure!
+ // Anyone can spoof this endpoint
+}
+```
+
+**✅ CORRECT:**
+```typescript
+export async function handleWebhook(req, res) {
+ const signature = req.headers['stripe-signature'];
+
+ const event = stripe.webhooks.constructEvent(
+ req.body,
+ signature,
+ webhookSecret // ← VERIFIED signature
+ );
+}
+```
+
+### Pitfall 5: Logging Sensitive Data
+
+**❌ WRONG:**
+```typescript
+console.log('Payment:', {
+ cardNumber: req.body.cardNumber, // ← VIOLATION!
+ cvv: req.body.cvv,
+});
+```
+
+**✅ CORRECT:**
+```typescript
+logger.info('Payment created', {
+ userId,
+ amount,
+ paymentIntentId, // ← Safe token
+ // NO card data
+});
+```
+
+---
+
+## Code Review Checklist
+
+**Before approving any payment-related PR, verify:**
+
+### Security
+- [ ] ❌ NO card data accepted in API (cardNumber, cvv, expiryDate)
+- [ ] ❌ NO card data stored in database (PAN, CVV, expiry)
+- [ ] ✅ Only Stripe tokens/IDs stored (pm_xxx, pi_xxx, cus_xxx)
+- [ ] ✅ Webhook signatures verified (constructEvent)
+- [ ] ✅ HTTPS enforced (no HTTP endpoints)
+- [ ] ✅ Input validation on all endpoints
+- [ ] ✅ No sensitive data in logs
+
+### Code Quality
+- [ ] TypeScript types defined
+- [ ] Error handling implemented
+- [ ] Logging added (info, warn, error)
+- [ ] Tests added/updated (unit + E2E)
+- [ ] Documentation updated
+
+### Stripe Integration
+- [ ] Payment Intents used (not deprecated APIs)
+- [ ] Stripe Elements used in frontend (not native inputs)
+- [ ] Client Secret format validated (pi_xxx_secret_yyy)
+- [ ] Metadata included in Stripe calls
+
+### Database
+- [ ] Parameterized queries (NO SQL injection)
+- [ ] Transactions used for multi-step operations
+- [ ] Indexes created for query performance
+- [ ] Migrations tested
+
+---
+
+## Deployment Checklist
+
+**Before deploying payment features to production:**
+
+### Environment Variables
+- [ ] `STRIPE_SECRET_KEY` set (sk_live_...)
+- [ ] `STRIPE_PUBLISHABLE_KEY` set (pk_live_...)
+- [ ] `STRIPE_WEBHOOK_SECRET` set (whsec_...)
+- [ ] `DATABASE_URL` configured
+- [ ] `JWT_SECRET` set (strong random key)
+
+### Stripe Configuration
+- [ ] Live mode API keys configured
+- [ ] Webhooks configured (payment_intent.*, customer.subscription.*)
+- [ ] Webhook endpoint HTTPS URL added
+- [ ] Test webhooks with Stripe CLI
+- [ ] Radar fraud detection enabled (recommended)
+
+### Security
+- [ ] SSL/TLS certificate valid (HTTPS)
+- [ ] HSTS header enabled
+- [ ] CSP header configured (allow stripe.com)
+- [ ] Rate limiting enabled (60 req/min recommended)
+- [ ] Firewall rules configured
+- [ ] Database backups enabled
+
+### Testing
+- [ ] All E2E tests passing (45+ tests)
+- [ ] Manual testing completed
+- [ ] Test payment with real card (Stripe test mode)
+- [ ] Webhook handling verified
+- [ ] Error scenarios tested
+
+### Monitoring
+- [ ] Logging configured (info, warn, error)
+- [ ] Error tracking enabled (Sentry, etc.)
+- [ ] Payment metrics dashboard
+- [ ] Alerts configured (failed payments, webhook errors)
+
+---
+
+## Troubleshooting
+
+### Common Issues
+
+#### Issue 1: "No such payment_intent"
+
+**Cause:** Invalid Payment Intent ID
+
+**Solution:**
+```typescript
+// Verify Payment Intent ID format
+if (!paymentIntentId.startsWith('pi_')) {
+ throw new Error('Invalid Payment Intent ID');
+}
+
+// Check Stripe dashboard for actual ID
+```
+
+#### Issue 2: "Webhook signature verification failed"
+
+**Cause:** Invalid signature or wrong webhook secret
+
+**Solution:**
+```typescript
+// 1. Verify webhook secret is correct
+console.log('Webhook Secret:', process.env.STRIPE_WEBHOOK_SECRET);
+
+// 2. Check raw body is used (not JSON parsed)
+app.post('/webhook', raw({ type: 'application/json' }), handler);
+
+// 3. Test with Stripe CLI
+// stripe listen --forward-to localhost:3000/api/v1/payments/webhook
+```
+
+#### Issue 3: "CardElement not rendering"
+
+**Cause:** Stripe not loaded or Elements context missing
+
+**Solution:**
+```typescript
+// 1. Wrap with Elements provider
+
+
+
+
+// 2. Check Stripe loaded
+const stripe = useStripe();
+if (!stripe) {
+ return Loading...
;
+}
+```
+
+#### Issue 4: "Payment stuck in 'pending'"
+
+**Cause:** Webhook not received or failed
+
+**Solution:**
+```bash
+# 1. Check webhook logs
+stripe webhook logs --limit 10
+
+# 2. Manually trigger webhook (for testing)
+stripe trigger payment_intent.succeeded
+
+# 3. Verify webhook endpoint is reachable
+curl -X POST https://api.example.com/api/v1/payments/webhook
+```
+
+---
+
+## Examples & Templates
+
+### Example 1: Wallet Deposit Flow (Complete)
+
+```typescript
+// Backend: payments.controller.ts
+export async function createDeposit(req, res) {
+ const { amount, currency } = req.body;
+
+ const paymentIntent = await stripe.paymentIntents.create({
+ amount: amount * 100,
+ currency,
+ metadata: { userId: req.user.id, type: 'deposit' },
+ });
+
+ await db.query(
+ 'INSERT INTO transactions (user_id, amount, payment_intent_id, status) VALUES ($1, $2, $3, $4)',
+ [req.user.id, amount, paymentIntent.id, 'pending']
+ );
+
+ res.json({ clientSecret: paymentIntent.client_secret });
+}
+
+// Frontend: DepositForm.tsx
+function DepositForm() {
+ const stripe = useStripe();
+ const elements = useElements();
+
+ const handleSubmit = async (e) => {
+ e.preventDefault();
+
+ const { clientSecret } = await fetch('/api/v1/payments/wallet/deposit', {
+ method: 'POST',
+ body: JSON.stringify({ amount: 100, currency: 'USD' }),
+ }).then(r => r.json());
+
+ const { error } = await stripe.confirmCardPayment(clientSecret, {
+ payment_method: { card: elements.getElement(CardElement) },
+ });
+
+ if (!error) {
+ alert('Deposit successful!');
+ }
+ };
+
+ return (
+
+ );
+}
+```
+
+### Example 2: Subscription Checkout (Stripe Hosted)
+
+```typescript
+// Backend: createCheckoutSession
+export async function createCheckoutSession(req, res) {
+ const { planId, billingCycle } = req.body;
+
+ const session = await stripe.checkout.sessions.create({
+ mode: 'subscription',
+ customer_email: req.user.email,
+ line_items: [{
+ price: getPriceId(planId, billingCycle),
+ quantity: 1,
+ }],
+ success_url: `${req.body.successUrl}?session_id={CHECKOUT_SESSION_ID}`,
+ cancel_url: req.body.cancelUrl,
+ metadata: { userId: req.user.id, planId },
+ });
+
+ res.json({ sessionId: session.id, url: session.url });
+}
+
+// Frontend: SubscribeButton.tsx
+async function handleSubscribe() {
+ const { url } = await fetch('/api/v1/payments/checkout', {
+ method: 'POST',
+ body: JSON.stringify({
+ planId: 'basic',
+ billingCycle: 'monthly',
+ successUrl: window.location.origin + '/success',
+ cancelUrl: window.location.origin + '/cancel',
+ }),
+ }).then(r => r.json());
+
+ window.location.href = url; // Redirect to Stripe
+}
+```
+
+---
+
+## Quick Reference
+
+### DO's ✅
+
+- ✅ Use Payment Intents (server-side processing)
+- ✅ Use Stripe Elements (client-side tokenization)
+- ✅ Verify webhook signatures
+- ✅ Store only tokens/IDs (pm_xxx, pi_xxx)
+- ✅ Use HTTPS everywhere
+- ✅ Log payment events (without sensitive data)
+- ✅ Write E2E tests for PCI-DSS compliance
+- ✅ Validate input on all endpoints
+- ✅ Use parameterized SQL queries
+
+### DON'Ts ❌
+
+- ❌ Accept card data in backend
+- ❌ Store PAN, CVV, or expiry in database
+- ❌ Create native card inputs
+- ❌ Store card data in React state
+- ❌ Skip webhook signature verification
+- ❌ Use HTTP (only HTTPS)
+- ❌ Log sensitive data
+- ❌ Concatenate SQL queries
+
+---
+
+## Support
+
+**Questions or Issues?**
+- Slack: #payments-support
+- Email: payments-team@trading-platform.com
+- Documentation: [ET-PAY-006: PCI-DSS Architecture](./especificaciones/ET-PAY-006-pci-dss-architecture.md)
+
+**Security Concerns?**
+- Email: security@trading-platform.com
+- **DO NOT** discuss card data in public channels
+
+---
+
+**Version:** 1.0.0
+**Last Updated:** 2026-01-26
+**Next Review:** 2026-07-26
+
+---
+
+*These guidelines are mandatory for all developers working on payment features. Non-compliance may result in PCI-DSS violations and severe penalties.*