# Flutter App Repayment API Integration Documentation

## Overview
This document outlines how the Flutter mobile application integrates with the LendCore Laravel API for loan repayment functionality. The integration supports M-Pesa STK Push payments with real-time status updates.

## Authentication
All API requests require authentication using Laravel Sanctum tokens:
```
Authorization: Bearer {token}
```

## API Endpoints

### 1. Fetch User Repayments
**GET** `/api/repayments`

**Purpose:** Retrieve all repayments for the authenticated user.

**Note:** `installment_number` can be `null` for legacy repayments.

**Response:**
```json
[
  {
    "id": 1,
    "loan_id": 1,
    "installment_number": 1,
    "due_date": "2024-01-15",
    "amount_due": "500.00",
    "amount_paid": "0.00",
    "balance": "500.00",
    "status": "pending",
    "is_active": true,
    "paid_at": null,
    "fine": null,
    "loan": {
      "id": 1,
      "status": "active",
      "weekly_installment": "500.00",
      "total_payable": "10000.00"
    },
    "created_at": "2024-01-01T00:00:00.000000Z",
    "updated_at": "2024-01-01T00:00:00.000000Z"
  }
]
```

### 2. Get Repayment Details with Payment History
**GET** `/api/repayments/{repayment_id}`

**Purpose:** Get detailed repayment information including all payment transactions.

**Response:**
```json
{
  "id": 1,
  "loan_id": 1,
  "installment_number": 1,
  "due_date": "2024-01-15",
  "amount_due": "500.00",
  "amount_paid": "250.00",
  "balance": "250.00",
  "status": "partial",
  "is_active": true,
  "paid_at": null,
  "fine": null,
  "loan": {
    "id": 1,
    "status": "active",
    "weekly_installment": "500.00",
    "total_payable": "10000.00"
  },
  "transactions": [
    {
      "id": 1,
      "amount": "250.00",
      "type": "payment",
      "status": "completed",
      "mpesa_transaction_id": "RCK7T...",
      "reference": "Loan #1 Repayment #1-1",
      "processed_at": "2024-01-10T14:30:00.000000Z",
      "created_at": "2024-01-10T14:25:00.000000Z"
    }
  ],
  "created_at": "2024-01-01T00:00:00.000000Z",
  "updated_at": "2024-01-10T14:30:00.000000Z"
}
```

### 3. Initiate Payment (STK Push)
**POST** `/api/repayments/{repayment_id}/pay`

**Purpose:** Initiate an M-Pesa STK Push payment for a repayment.

**Request Body:**
```json
{
  "amount": 250.00,
  "mpesa_phone": "254712345678"
}
```

**Success Response (STK Push initiated):**
```json
{
  "message": "M-Pesa prompt sent to 254712345678. Please check your phone to complete payment.",
  "transaction_id": 1,
  "checkout_request_id": "ws_CO_010120241230456789",
  "status": "pending"
}
```

**Error Response:**
```json
{
  "message": "Failed to initiate M-Pesa payment. Please try again."
}
```

### 4. Check Payment Status
**GET** `/api/repayments/{repayment_id}/pay/status`

**Purpose:** Poll for the latest payment transaction status.

**Response:**
```json
{
  "status": "completed",
  "message": "Payment completed successfully.",
  "transaction_id": 1,
  "amount": "250.00",
  "mpesa_transaction_id": "RCK7T...",
  "processed_at": "2024-01-10T14:30:00.000000Z"
}
```

## Flutter App Integration Roadmap

### Phase 1: Data Fetching
1. **Implement Authentication**
   - Store Sanctum token securely
   - Include Bearer token in all API requests

2. **Create Repayment Models**
   ```dart
   class Repayment {
     final int id;
     final int loanId;
     final int? installmentNumber;  // Optional - can be null
     final DateTime dueDate;
     final double amountDue;
     final double amountPaid;
     final double balance;
     final String status;
     final List<Transaction> transactions;
     // ... other fields
   }

   class Transaction {
     final int id;
     final double amount;
     final String type;
     final String status;
     final String? mpesaTransactionId;
     final String reference;
     final DateTime? processedAt;
     // ... other fields
   }
   ```

   **Important Note: Making `installmentNumber` Optional**

   **Why Make it Optional?**

   From the Laravel migration, `installment_number` is defined as:
   ```php
   $table->integer('installment_number')->nullable()->after('loan_id');
   ```

   This means:
   - ✅ **Can be null** for legacy repayments
   - ✅ **Should be optional** in your Flutter model
   - ✅ **Constructor call issue** is likely due to treating it as required

   **Fix the Flutter Model Constructor:**

   ```dart
   class Repayment {
     final int id;
     final int loanId;
     final int? installmentNumber;  // Make this optional
     final DateTime dueDate;
     final double amountDue;
     final double amountPaid;
     final double balance;
     final String status;
     final List<Transaction> transactions;
     
     // Constructor
     Repayment({
       required this.id,
       required this.loanId,
       this.installmentNumber,  // Optional parameter
       required this.dueDate,
       required this.amountDue,
       required this.amountPaid,
       required this.balance,
       required this.status,
       required this.transactions,
     });
     
     // Factory constructor for JSON parsing
     factory Repayment.fromJson(Map<String, dynamic> json) {
       return Repayment(
         id: json['id'],
         loanId: json['loan_id'],
         installmentNumber: json['installment_number'],  // Can be null
         dueDate: DateTime.parse(json['due_date']),
         amountDue: double.parse(json['amount_due']),
         amountPaid: double.parse(json['amount_paid']),
         balance: double.parse(json['balance']),
         status: json['status'],
         transactions: (json['transactions'] as List?)
             ?.map((t) => Transaction.fromJson(t))
             ?.toList() ?? [],
       );
     }
   }
   ```

   **Fix the Constructor Call in `loan_provider.dart`:**

   The issue is likely that you're calling the constructor like this:
   ```dart
   // ❌ Wrong - treating installmentNumber as required
   Repayment(
     id: data['id'],
     loanId: data['loan_id'],
     installmentNumber: data['installment_number'],  // Error if null
     // ... other fields
   )
   ```

   **Fix it to:**
   ```dart
   // ✅ Correct - installmentNumber is optional
   Repayment(
     id: data['id'],
     loanId: data['loan_id'],
     installmentNumber: data['installment_number'],  // Can be null
     // ... other fields
   )
   ```

   **Handle Null Values in UI:**

   When displaying the installment number in your Flutter app:
   ```dart
   Text('Installment: ${repayment.installmentNumber ?? 'N/A'}')
   ```

   This ensures your app handles both legacy repayments (without installment numbers) and new ones (with installment numbers).

3. **Fetch Repayments List**
   - Call `GET /api/repayments`
   - Display repayments in a list view
   - Show status indicators (pending, partial, paid, overdue)

### Phase 2: Payment History
1. **View Payment Details**
   - Call `GET /api/repayments/{id}` for detailed view
   - Display transaction history
   - Show M-Pesa transaction IDs for completed payments

2. **Handle Multiple Payments**
   - Support partial payments (multiple transactions per repayment)
   - Calculate remaining balance dynamically

### Phase 3: STK Push Payment Integration
1. **Payment Initiation**
   - Create payment form with amount and phone number inputs
   - Validate Kenyan phone number format (254XXXXXXXXX)
   - Submit to `POST /api/repayments/{id}/pay`

2. **Real-time Status Updates**
   - Start polling `GET /api/repayments/{id}/pay/status` immediately after payment initiation
   - Poll every 3-5 seconds for up to 2 minutes
   - Update UI based on status:
     - `pending`: Show "Processing payment..."
     - `completed`: Show success message and refresh data
     - `failed`: Show error message
     - Timeout after 120 seconds: Show timeout message

3. **UI States**
   ```dart
   enum PaymentState {
     idle,
     initiating,
     pending,
     completed,
     failed,
     timeout
   }
   ```

### Phase 4: Data Synchronization
1. **Automatic Data Refresh**
   - After successful payment, automatically fetch updated repayment data
   - Update local models and UI
   - Refresh loan status if needed

2. **Error Handling**
   - Network errors: Retry mechanism
   - API errors: User-friendly error messages
   - STK Push failures: Allow retry

## Data Flow for Flutter App

### 1. App Startup
- Authenticate user and get token
- Fetch all repayments: `GET /api/repayments`

### 2. Viewing Repayment Details
- User selects repayment from list
- Fetch detailed data: `GET /api/repayments/{id}`
- Display payment history and current balance

### 3. Making a Payment
```
User enters amount and phone → POST /api/repayments/{id}/pay
                              ↓
                    STK Push initiated (pending status)
                              ↓
                    Start polling GET /api/repayments/{id}/pay/status
                              ↓
                    Status updates → UI reflects changes
                              ↓
                    Success → Fetch updated data → Show success
```

### 4. Data Refresh After Payment
- On payment completion, call `GET /api/repayments/{id}` again
- Update local data models
- Refresh UI components

## Verification Between Laravel and Flutter

### Authentication Verification
- Laravel validates Sanctum tokens on every request
- Flutter includes `Authorization: Bearer {token}` header
- Invalid tokens return 401 Unauthorized

### Data Integrity
- Laravel ensures users can only access their own repayments
- Repayment ownership verified by `repayment.loan.user_id === request.user().id`
- Flutter receives filtered data based on authenticated user

### Payment Security
- STK Push requests validated server-side
- Phone numbers must match Kenyan format
- Transaction amounts validated against repayment balances
- All payment attempts logged in audit trail

### Status Synchronization
- Transaction status updates happen server-side only
- Flutter polls for status changes
- No client-side status manipulation possible

## Error Handling

### API Error Responses
```json
{
  "message": "Payment error: Invalid phone number",
  "errors": {
    "mpesa_phone": ["The mpesa phone format is invalid."]
  }
}
```

### Network Errors
- Implement retry logic with exponential backoff
- Show offline indicators
- Queue requests for when connectivity returns

### Payment Timeouts
- STK Push timeout after 120 seconds
- Clear pending status
- Allow user to retry payment

## Testing Checklist

### Unit Tests
- [ ] Repayment model parsing
- [ ] Transaction model parsing
- [ ] Payment state management
- [ ] Phone number validation

### Integration Tests
- [ ] Authentication flow
- [ ] Repayments list fetching
- [ ] Payment initiation
- [ ] Status polling
- [ ] Data refresh after payment

### End-to-End Tests
- [ ] Complete payment flow with mock M-Pesa
- [ ] Error scenarios (network failure, invalid phone)
- [ ] Timeout handling
- [ ] Data synchronization

## Security Considerations

1. **Token Storage**: Use secure storage for Sanctum tokens
2. **HTTPS Only**: All API calls must use HTTPS
3. **Input Validation**: Validate all user inputs client-side and server-side
4. **Rate Limiting**: Implement rate limiting for payment endpoints
5. **Audit Logging**: All payment attempts logged server-side

## Performance Optimization

1. **Caching**: Cache repayment data locally
2. **Pagination**: Implement pagination for large repayment lists
3. **Background Sync**: Sync data in background when app is active
4. **Minimal Polling**: Poll payment status efficiently (not too frequent)

This integration ensures a seamless, secure, and user-friendly repayment experience in the Flutter mobile application.</content>
<parameter name="filePath">c:\xampp\htdocs\LendCore\FLUTTER_APP_REPAYMENT_API_INTEGRATION.md