# PayPal Integration Guide

## Overview

This document provides comprehensive documentation for the PayPal integration in the Schematics backend application. The integration supports subscription-based payments with multiple tiers and includes webhook handling for real-time payment status updates.

## Table of Contents

- [Architecture](#architecture)
- [Environment Setup](#environment-setup)
- [Database Schema](#database-schema)
- [API Endpoints](#api-endpoints)
- [Implementation Details](#implementation-details)
- [Webhook Handling](#webhook-handling)
- [Error Handling](#error-handling)
- [Testing](#testing)
- [Security Considerations](#security-considerations)
- [Troubleshooting](#troubleshooting)

## Architecture

The PayPal integration follows a layered architecture pattern:

```
Controller Layer (SubscriptionController)
    ↓
Service Layer (SubscriptionServices)
    ↓
Repository Layer (SubscriptionRepositry)
    ↓
PayPal API + Database (Prisma)
```

### Key Components

- **SubscriptionController**: Handles HTTP requests and responses
- **SubscriptionServices**: Business logic and webhook event processing
- **SubscriptionRepositry**: PayPal API interactions and database operations
- **Redis Cache**: Caching for PayPal packages to improve performance

## Environment Setup

### Required Environment Variables

Add the following variables to your `.env` file:

```env
# PayPal Configuration
PAYPAL_CLIENT_ID=your_paypal_client_id
PAYPAL_SECRET_KEY=your_paypal_secret_key
PAYPAL_WEBHOOK_ID=your_webhook_id
PAYPAL_ACCESS_TOKEN=your_access_token  # Optional, will be generated automatically

# Frontend URL for redirects
FRONTEND_URL=http://localhost:3000  # or your production URL
```

### PayPal Developer Setup

1. **Create PayPal Developer Account**
   - Go to [PayPal Developer Portal](https://developer.paypal.com/)
   - Create a new application
   - Note down the Client ID and Secret

2. **Configure Webhooks**
   - In PayPal Developer Console, create a webhook
   - Set the webhook URL to: `https://your-domain.com/api/subscription/webhook`
   - Subscribe to these events:
     - `CHECKOUT.ORDER.APPROVED`
     - `PAYMENT.CAPTURE.COMPLETED`
     - `BILLING.SUBSCRIPTION.CREATED`
     - `BILLING.SUBSCRIPTION.ACTIVATED`
     - `BILLING.SUBSCRIPTION.CANCELLED`

3. **Environment Configuration**
   - For development: Use PayPal Sandbox
   - For production: Use PayPal Live environment
   - Update API endpoints accordingly

## Database Schema

### Subscription Tiers

The application supports three subscription tiers:

```typescript
enum TierTypeProps {
  FREE_TIER    // Free tier with limited features
  HEALING      // $19.99/month - Healing features
  THERAPY      // $29.99/month - Full therapy features
}
```

### Key Database Models

#### Users Table

```sql
-- Users table includes subscription information
subscriptionTier TierTypeProps @default(FREE_TIER)
isSubscribe      Boolean       @default(false)
```

#### Subscriptions Table

```sql
model Subscriptions {
  id             String   @id @default(cuid())
  subscriptionId String   -- PayPal subscription ID
  userId         String   -- Reference to user
  createdAt      DateTime @default(now())
  updatedAt      DateTime @updatedAt
}
```

#### Payments Table

```sql
model Payment {
  id             String        @id @default(cuid())
  userId         String        -- Reference to user
  amount         Float         -- Payment amount
  currency       String        @default("USD")
  paymentMethod  String        -- "PayPal"
  status         PaymentStatus -- PENDING, COMPLETED, FAILED, etc.
  transactionId  String?       -- PayPal transaction ID
  subscriptionId String?       -- Reference to subscription
  createdAt      DateTime      @default(now())
  updatedAt      DateTime      @updatedAt
}
```

## API Endpoints

### 1. Get Available Packages

**Endpoint:** `GET /api/subscription/`

**Description:** Retrieves available PayPal subscription packages

**Response:**

```json
{
  "success": true,
  "data": {
    "plans": [
      {
        "id": "P-1234567890",
        "name": "Healing Plan",
        "description": "Monthly healing subscription",
        "billing_cycles": [
          {
            "frequency": {
              "interval_unit": "MONTH",
              "interval_count": 1
            },
            "tenure_type": "REGULAR",
            "sequence": 1,
            "total_cycles": 0,
            "pricing_scheme": {
              "fixed_price": {
                "value": "19.99",
                "currency_code": "USD"
              }
            }
          }
        ]
      }
    ]
  },
  "message": "Packages retrieved successfully"
}
```

### 2. Create Checkout Session

**Endpoint:** `POST /api/subscription/checkout`

**Headers:** `Authorization: Bearer <jwt_token>`

**Request Body:**

```json
{
  "planId": "P-1234567890"
}
```

**Response:**

```json
{
  "success": true,
  "data": {
    "id": "ORDER-1234567890",
    "status": "CREATED",
    "links": [
      {
        "href": "https://www.sandbox.paypal.com/checkoutnow?token=ORDER-1234567890",
        "rel": "approve",
        "method": "GET"
      }
    ]
  },
  "message": "Checkout created successfully"
}
```

### 3. Capture Order

**Endpoint:** `POST /api/subscription/capture/:orderId`

**Description:** Captures a PayPal order after user approval

**Response:**

```json
{
  "success": true,
  "data": {
    "id": "ORDER-1234567890",
    "status": "COMPLETED",
    "purchase_units": [
      {
        "reference_id": "subscription_user123_1234567890",
        "amount": {
          "currency_code": "USD",
          "value": "19.99"
        }
      }
    ]
  },
  "message": "Order captured successfully"
}
```

### 4. Get User Subscription

**Endpoint:** `GET /api/subscription/user`

**Headers:** `Authorization: Bearer <jwt_token>`

**Response:**

```json
{
  "success": true,
  "data": {
    "userId": "user123",
    "email": "user@example.com",
    "subscriptionTier": "HEALING",
    "isSubscribe": true,
    "currentSubscription": {
      "id": "sub123",
      "subscriptionId": "I-BW452GLLEP1G",
      "createdAt": "2024-01-01T00:00:00.000Z"
    }
  },
  "message": "User subscription retrieved successfully"
}
```

### 5. Webhook Endpoint

**Endpoint:** `POST /api/subscription/webhook`

**Description:** Handles PayPal webhook events

**Headers:** PayPal-specific headers for webhook verification

## Implementation Details

### Authentication Flow

1. **Access Token Generation**

   ```typescript
   private async makeAccessToken(): Promise<string> {
     const response = await fetch('https://api-m.sandbox.paypal.com/v1/oauth2/token', {
       method: 'POST',
       headers: {
         'Content-Type': 'application/x-www-form-urlencoded',
         'Authorization': 'Basic ' + Buffer.from(`${clientId}:${secret}`).toString('base64'),
       },
       body: new URLSearchParams({ grant_type: 'client_credentials' }).toString(),
     });

     const json = await response.json();
     return json.access_token;
   }
   ```

2. **Order Creation**

   ```typescript
   public async createPayPalOrder(planId: string, userId: string): Promise<any> {
     const orderData = {
       intent: 'CAPTURE',
       purchase_units: [{
         reference_id: `subscription_${userId}_${Date.now()}`,
         amount: {
           currency_code: 'USD',
           value: '0.00' // Set by the plan
         }
       }],
       application_context: {
         brand_name: 'Schematics',
         landing_page: 'NO_PREFERENCE',
         user_action: 'SUBSCRIBE_NOW',
         return_url: `${ENV.FRONTEND_URL}/dashboard`,
         cancel_url: `${ENV.FRONTEND_URL}/pricing`
       }
     };

     // Make API call to PayPal
   }
   ```

### Caching Strategy

The application uses Redis to cache both PayPal packages and access tokens:

#### Access Token Caching

```typescript
private async makeAccessToken(): Promise<string> {
  const cacheKey = 'paypal:access_token';
  const cacheTTL = 32400; // 9 hours (PayPal tokens expire in 9 hours)

  // Try Redis cache first
  const cachedToken = await RedisUtils.get(cacheKey, 'subscription');
  if (cachedToken && typeof cachedToken === 'string') {
    console.log('🔑 PayPal access token retrieved from Redis cache');
    return cachedToken;
  }

  // Fetch new token from PayPal API and cache
  const response = await fetch('https://api-m.sandbox.paypal.com/v1/oauth2/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Authorization': 'Basic ' + Buffer.from(`${clientId}:${secret}`).toString('base64'),
    },
    body: new URLSearchParams({ grant_type: 'client_credentials' }).toString(),
  });

  const json = await response.json();
  const accessToken = json.access_token;

  // Store in Redis cache
  await RedisUtils.set(cacheKey, accessToken, { ttl: cacheTTL, prefix: 'subscription' });

  return accessToken;
}
```

#### Packages Caching

```typescript
public async getPaypalPackages(): Promise<any> {
  const cacheKey = 'paypal:packages';
  const cacheTTL = 1800; // 30 minutes

  // Try Redis cache first
  const cachedPackages = await RedisUtils.get(cacheKey, 'subscription');
  if (cachedPackages) {
    return cachedPackages;
  }

  // Fetch from PayPal API and cache
  const packages = await this.fetchFromPayPal();
  await RedisUtils.set(cacheKey, packages, { ttl: cacheTTL, prefix: 'subscription' });

  return packages;
}
```

## Webhook Handling

### Webhook Verification

All webhooks are verified using PayPal's signature verification:

```typescript
public async verifyPayPalWebhook(headers: any, body: string): Promise<boolean> {
  const webhookData = {
    auth_algo: headers['paypal-auth-algo'],
    cert_id: headers['paypal-cert-id'],
    transmission_id: headers['paypal-transmission-id'],
    transmission_sig: headers['paypal-transmission-sig'],
    transmission_time: headers['paypal-transmission-time'],
    webhook_id: ENV.PAYPAL_WEBHOOK_ID,
    webhook_event: JSON.parse(body)
  };

  const response = await fetch('https://api-m.sandbox.paypal.com/v1/notifications/verify-webhook-signature', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`
    },
    body: JSON.stringify(webhookData)
  });

  const result = await response.json();
  return result.verification_status === 'SUCCESS';
}
```

### Event Handling

The system handles multiple webhook events:

#### Payment Completed

```typescript
private async handlePaymentCompleted(event: any): Promise<any> {
  const payment = event.resource;
  const userId = this.extractUserId(payment);

  // Create payment record
  await repository.createPaymentRecord(
    userId,
    payment.id,
    parseFloat(payment.amount?.value || '0'),
    'COMPLETED'
  );

  // Determine tier based on amount
  let tier: TierTypeProps = 'FREE_TIER';
  const amount = parseFloat(payment.amount?.value || '0');

  if (amount >= 29.99) {
    tier = 'THERAPY';
  } else if (amount >= 19.99) {
    tier = 'HEALING';
  }

  // Update user subscription
  await repository.updateUserSubscriptionTier(userId, tier, payment.id);

  return { status: 'payment_completed', userId, tier };
}
```

#### Subscription Events

- **Created**: Logs subscription creation
- **Activated**: Updates user tier based on plan
- **Cancelled**: Downgrades user to free tier

## Error Handling

### Common Error Scenarios

1. **Invalid Credentials**

   ```typescript
   if (!ENV.PAYPAL_CLIENT_ID || !ENV.PAYPAL_SECRET_KEY) {
     throw new Error('Missing PayPal credentials.');
   }
   ```

2. **API Errors**

   ```typescript
   if (!response.ok) {
     const body = await response.text();
     throw new Error(
       `PayPal API error: ${response.status} ${response.statusText} - ${body}`
     );
   }
   ```

3. **Webhook Verification Failure**
   ```typescript
   const isValid = await repository.verifyPayPalWebhook(headers, body);
   if (!isValid) {
     throw new Error('Invalid webhook signature');
   }
   ```

### Error Response Format

```json
{
  "success": false,
  "message": "Error description",
  "error": "Detailed error information"
}
```

## Testing

### Sandbox Testing

1. **Use PayPal Sandbox**
   - All API calls use sandbox endpoints
   - Use sandbox test accounts for payments

2. **Test Scenarios**
   - Successful payment flow
   - Failed payment handling
   - Webhook event processing
   - Subscription lifecycle management

### Test Data

```typescript
// Test user IDs for different scenarios
const testUsers = {
  successfulPayment: 'user_success_123',
  failedPayment: 'user_fail_456',
  subscriptionCancel: 'user_cancel_789',
};
```

## Security Considerations

### 1. Webhook Security

- Always verify webhook signatures
- Use HTTPS for webhook endpoints
- Validate webhook payload structure

### 2. Data Protection

- Store minimal payment data
- Use secure database connections
- Implement proper access controls

### 3. API Security

- Use environment variables for credentials
- Implement rate limiting
- Validate all input parameters

### 4. User Data

- Encrypt sensitive user information
- Implement proper authentication
- Use secure session management

## Troubleshooting

### Common Issues

#### 1. Webhook Not Receiving Events

**Symptoms:** Webhooks not being called by PayPal

**Solutions:**

- Verify webhook URL is accessible
- Check webhook configuration in PayPal Developer Console
- Ensure webhook events are properly subscribed
- Test webhook endpoint manually

#### 2. Authentication Failures

**Symptoms:** 401 Unauthorized errors

**Solutions:**

- Verify PayPal credentials in environment variables
- Check if using correct environment (sandbox vs live)
- Ensure access token is not expired
- Verify API endpoint URLs

#### 3. Order Capture Failures

**Symptoms:** Orders not being captured successfully

**Solutions:**

- Verify order ID is correct
- Check order status before capture
- Ensure user has approved the payment
- Verify capture endpoint implementation

#### 4. Cache Issues

**Symptoms:** Stale package data or expired access tokens

**Solutions:**

- Clear PayPal packages cache: `await repository.clearPaypalPackagesCache()`
- Clear access token cache: `await repository.clearPaypalAccessTokenCache()`
- Check cache TTL settings (packages: 30 min, tokens: 9 hours)
- Verify Redis connection
- Monitor cache hit/miss ratios
- Get cache info: `await repository.getPaypalAccessTokenCacheInfo()`

### Debugging Tips

1. **Enable Logging**

   ```typescript
   console.log('PayPal API Response:', response);
   console.log('Webhook Event:', webhookEvent);
   ```

2. **Check PayPal Developer Console**
   - Monitor API calls
   - Review webhook delivery logs
   - Check for error messages

3. **Database Queries**

   ```sql
   -- Check user subscription status
   SELECT id, email, subscriptionTier, isSubscribe
   FROM users
   WHERE id = 'user_id';

   -- Check payment records
   SELECT * FROM payments
   WHERE userId = 'user_id'
   ORDER BY createdAt DESC;
   ```

### Performance Optimization

1. **Caching Strategy**
   - Cache PayPal packages for 30 minutes
   - Use Redis for session storage
   - Implement cache invalidation

2. **Database Optimization**
   - Index frequently queried fields
   - Use connection pooling
   - Optimize query patterns

3. **API Optimization**
   - Batch API calls where possible
   - Implement retry logic
   - Use async/await properly

## Production Deployment

### Environment Configuration

1. **Update API Endpoints**

   ```typescript
   // Change from sandbox to live
   const baseUrl =
     ENV.NODE_ENV === 'production'
       ? 'https://api-m.paypal.com'
       : 'https://api-m.sandbox.paypal.com';
   ```

2. **Update Webhook URL**
   - Use production domain
   - Ensure HTTPS is enabled
   - Update PayPal Developer Console

3. **Security Hardening**
   - Use strong environment variables
   - Enable rate limiting
   - Implement monitoring

### Monitoring

1. **Key Metrics**
   - Payment success rate
   - Webhook delivery success
   - API response times
   - Error rates

2. **Alerts**
   - Failed webhook deliveries
   - High error rates
   - Payment processing failures

## Conclusion

This PayPal integration provides a robust foundation for subscription-based payments in the Schematics application. The implementation includes proper error handling, security measures, and comprehensive webhook support for real-time payment processing.

For additional support or questions, refer to:

- [PayPal Developer Documentation](https://developer.paypal.com/docs/)
- [PayPal API Reference](https://developer.paypal.com/docs/api/)
- [Webhook Documentation](https://developer.paypal.com/docs/api/webhooks/)
