# Payment System Documentation > **Version:** 1.6.0 > **Last Updated:** January 8, 2026 > **Status:** Production Ready This document provides comprehensive documentation of the IGNY8 payment system architecture, implementation, and flows. --- ## Table of Contents 1. [System Overview](#system-overview) 2. [Payment Entry Points](#payment-entry-points) 3. [Backend Architecture](#backend-architecture) 4. [Frontend Architecture](#frontend-architecture) 5. [Payment Flows](#payment-flows) 6. [Country-Based Payment Rules](#country-based-payment-rules) 7. [Webhook Processing](#webhook-processing) 8. [Models Reference](#models-reference) 9. [Security Features](#security-features) --- ## System Overview ### Supported Payment Methods | Method | Type | Regions | Use Cases | |--------|------|---------|-----------| | **Stripe** | Credit/Debit Card | Global | Subscriptions, Credit packages | | **PayPal** | PayPal account | Global (except PK) | Subscriptions, Credit packages | | **Bank Transfer** | Manual | Pakistan (PK) | Subscriptions, Credit packages | ### Payment Method Selection Logic ``` ┌────────────────────────────────────────────────────────┐ │ Country-Based Payment Rules │ ├────────────────────────────────────────────────────────┤ │ │ │ Global Users (non-PK): │ │ ✅ Stripe (Credit/Debit Card) │ │ ✅ PayPal │ │ ❌ Bank Transfer (not available) │ │ │ │ Pakistan Users (PK): │ │ ✅ Stripe (Credit/Debit Card) │ │ ❌ PayPal (not available in PK) │ │ ✅ Bank Transfer (manual) │ │ │ └────────────────────────────────────────────────────────┘ ``` ### Architecture Overview ``` ┌─────────────────────────────────────────────────────────────────┐ │ PAYMENT SYSTEM FLOW │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Signup │───────▶ │ /account/ │ │ │ │ (no pay) │ │ plans │ │ │ └──────────────┘ └──────┬───────┘ │ │ │ │ │ ┌─────────────┴─────────────┐ │ │ │ │ │ │ New User? Existing User? │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ PendingPay- │ │ Plans/Billing│ │ │ │ mentView │ │ Dashboard │ │ │ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ ┌─────────┼─────────┐ ┌────────┼────────┐ │ │ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ▼ │ │ Stripe PayPal Bank Upgrade Credits Manage │ │ Transfer │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## Payment Entry Points ### 1. Signup Flow **File:** `frontend/src/components/auth/SignUpFormUnified.tsx` **Simplified Signup (No Payment on Signup):** - User selects plan and provides details - Account created with `status='pending_payment'` for paid plans - User redirected to `/account/plans` to complete payment - No payment gateway redirect from signup page ```typescript // Signup flow creates account only, no checkout const handleSignup = async (data) => { const result = await register({ email, password, plan_slug, billing_country }); // Redirect to plans page for payment navigate('/account/plans'); }; ``` ### 2. Plans & Billing Page **File:** `frontend/src/pages/account/PlansAndBillingPage.tsx` Central hub for all payment-related actions: **For New Users (pending_payment):** - Shows `PendingPaymentView` component - Full-page payment interface - Invoice details and payment method selection **For Existing Users:** - Current plan and subscription status - Credit balance and purchase - Invoice history and downloads - Subscription management ### 3. PendingPaymentView Component **File:** `frontend/src/components/billing/PendingPaymentView.tsx` Full-page payment interface for new users: - Displays invoice details and plan info - Payment method selection based on country - Stripe/PayPal redirect or Bank Transfer form - Status checking for bank transfer submissions ### 4. Bank Transfer Form **File:** `frontend/src/components/billing/BankTransferForm.tsx` Manual payment submission for Pakistan users: - Bank account details display - Transaction reference input - File upload for payment proof - Submission and status tracking --- ## Backend Architecture ### Service Layer #### StripeService **File:** `backend/igny8_core/business/billing/services/stripe_service.py` | Method | Description | |--------|-------------| | `create_checkout_session()` | Create subscription checkout | | `create_credit_checkout_session()` | Create credit package checkout | | `create_billing_portal_session()` | Customer billing portal | | `get_or_create_customer()` | Stripe customer management | | `construct_webhook_event()` | Verify webhook signatures | #### PayPalService **File:** `backend/igny8_core/business/billing/services/paypal_service.py` | Method | Description | |--------|-------------| | `create_order()` | Create one-time payment order | | `create_subscription_order()` | Create subscription order | | `capture_order()` | Capture approved payment | | `verify_webhook_signature()` | Webhook verification | #### InvoiceService **File:** `backend/igny8_core/business/billing/services/invoice_service.py` | Method | Description | |--------|-------------| | `create_subscription_invoice()` | Invoice for plan subscription | | `create_credit_package_invoice()` | Invoice for credit purchase | | `mark_paid()` | Mark invoice as paid | | `generate_pdf()` | Generate PDF invoice | #### PaymentService **File:** `backend/igny8_core/business/billing/services/payment_service.py` | Method | Description | |--------|-------------| | `create_stripe_payment()` | Record Stripe payment | | `create_paypal_payment()` | Record PayPal payment | | `create_manual_payment()` | Record bank transfer | | `approve_manual_payment()` | Admin approval | ### API Endpoints #### Stripe Endpoints | Endpoint | Method | Description | |----------|--------|-------------| | `/v1/billing/stripe/config/` | GET | Publishable key | | `/v1/billing/stripe/checkout/` | POST | Create checkout session | | `/v1/billing/stripe/credit-checkout/` | POST | Credit package checkout | | `/v1/billing/stripe/billing-portal/` | POST | Billing portal | | `/v1/billing/webhooks/stripe/` | POST | Webhook handler | #### PayPal Endpoints | Endpoint | Method | Description | |----------|--------|-------------| | `/v1/billing/paypal/config/` | GET | Client ID | | `/v1/billing/paypal/create-order/` | POST | Credit package order | | `/v1/billing/paypal/create-subscription-order/` | POST | Subscription order | | `/v1/billing/paypal/capture-order/` | POST | Capture payment | | `/v1/billing/webhooks/paypal/` | POST | Webhook handler | #### Invoice Endpoints | Endpoint | Method | Description | |----------|--------|-------------| | `/v1/billing/invoices/` | GET | List invoices | | `/v1/billing/invoices/{id}/` | GET | Invoice detail | | `/v1/billing/invoices/{id}/download_pdf/` | GET | Download PDF | #### Payment Endpoints | Endpoint | Method | Description | |----------|--------|-------------| | `/v1/billing/payments/` | GET | List payments | | `/v1/billing/payments/manual/` | POST | Submit bank transfer | | `/v1/billing/admin/payments/confirm/` | POST | Admin approve/reject | --- ## Frontend Architecture ### Services **File:** `frontend/src/services/billing.api.ts` Key functions: ```typescript // Gateway availability (country-based) getAvailablePaymentGateways(userCountry?: string) // Subscription helpers subscribeToPlan(planId, gateway, options) purchaseCredits(packageId, gateway, options) // Stripe functions createStripeCheckout(planId, options) createStripeCreditCheckout(packageId, options) openStripeBillingPortal(returnUrl) // PayPal functions createPayPalSubscriptionOrder(planId, options) createPayPalCreditOrder(packageId, options) capturePayPalOrder(orderId, metadata) // Manual payment submitManualPayment(invoiceId, data) ``` ### Components | Component | File | Purpose | |-----------|------|---------| | `PendingPaymentView` | `/components/billing/PendingPaymentView.tsx` | New user payment | | `BankTransferForm` | `/components/billing/BankTransferForm.tsx` | Bank transfer submission | | `PendingPaymentBanner` | `/components/billing/PendingPaymentBanner.tsx` | Alert for pending payments | | `PaymentGatewaySelector` | `/components/billing/PaymentGatewaySelector.tsx` | Gateway selection UI | | `PayInvoiceModal` | `/components/billing/PayInvoiceModal.tsx` | Pay invoice modal | --- ## Payment Flows ### Flow 1: New User Signup with Stripe ``` 1. User submits signup form with plan 2. Backend creates: - User account - Account (status='pending_payment') - Subscription (status='pending_payment') - Invoice (status='pending') 3. User redirected to /account/plans 4. PendingPaymentView displays 5. User selects Stripe, clicks Pay 6. Redirect to Stripe Checkout 7. User completes payment 8. Stripe webhook received: - Payment recorded - Invoice marked paid - Account activated - Credits added 9. User redirected back to /account/plans 10. Success message, dashboard displays ``` ### Flow 2: New User with PayPal (Non-PK) ``` 1. Same as Stripe steps 1-4 5. User selects PayPal, clicks Pay 6. PayPal order created 7. Redirect to PayPal approval 8. User approves on PayPal 9. Redirect back with order_id 10. Frontend calls capture-order 11. Backend processes: - Payment captured - Payment recorded - Invoice marked paid - Account activated - Credits added 12. Success displayed ``` ### Flow 3: Pakistan User with Bank Transfer ``` 1. Same as signup steps 1-4 5. User sees Stripe + Bank Transfer options 6. User selects Bank Transfer 7. BankTransferForm displays: - Bank details (SCB Pakistan) - Reference input - Proof upload option 8. User makes transfer, submits form 9. Backend creates: - Payment (status='pending_approval') 10. User sees "Awaiting Approval" status 11. Admin reviews in Django Admin 12. Admin approves: - Payment marked succeeded - Invoice marked paid - Account activated - Credits added 13. User receives email confirmation ``` ### Flow 4: Existing User Buys Credits ``` 1. User on /account/plans clicks "Buy Credits" 2. Credit package selection modal 3. User selects package and gateway 4. For Stripe/PayPal: redirect flow 5. For Bank Transfer: form submission 6. On success: credits added to account ``` --- ## Country-Based Payment Rules ### Implementation in Frontend ```typescript // billing.api.ts export async function getAvailablePaymentGateways(userCountry?: string) { const [stripeAvailable, paypalAvailable] = await Promise.all([ isStripeConfigured(), isPayPalConfigured(), ]); const isPakistan = userCountry?.toUpperCase() === 'PK'; return { stripe: stripeAvailable, // PayPal: NOT available for Pakistan paypal: !isPakistan && paypalAvailable, // Bank Transfer: ONLY for Pakistan manual: isPakistan, }; } ``` ### Usage in Components ```typescript // PendingPaymentView.tsx const isPakistan = userCountry === 'PK'; // Load gateways with country filter const gateways = await getAvailablePaymentGateways(userCountry); // Show appropriate options const paymentOptions = [ { type: 'stripe', ... }, // Always shown if configured isPakistan ? { type: 'manual', ... } : { type: 'paypal', ... }, ]; ``` --- ## Webhook Processing ### Stripe Webhooks **Endpoint:** `POST /v1/billing/webhooks/stripe/` | Event | Handler Action | |-------|----------------| | `checkout.session.completed` | Activate subscription, add credits | | `invoice.paid` | Add renewal credits | | `invoice.payment_failed` | Send notification | | `customer.subscription.updated` | Sync changes | | `customer.subscription.deleted` | Cancel subscription | **Idempotency:** Checks `WebhookEvent` model before processing: ```python # Check if already processed if WebhookEvent.objects.filter( provider='stripe', event_id=event_id, status='processed' ).exists(): return # Already handled ``` ### PayPal Webhooks **Endpoint:** `POST /v1/billing/webhooks/paypal/` | Event | Handler Action | |-------|----------------| | `CHECKOUT.ORDER.APPROVED` | Auto-capture if configured | | `PAYMENT.CAPTURE.COMPLETED` | Mark succeeded, add credits | | `PAYMENT.CAPTURE.DENIED` | Mark failed | | `BILLING.SUBSCRIPTION.ACTIVATED` | Activate subscription | **Signature Verification:** Enabled and enforced: ```python is_valid = service.verify_webhook_signature(...) if not is_valid: return Response({'error': 'Invalid signature'}, status=400) ``` --- ## Models Reference ### Invoice Model ```python class Invoice(AccountBaseModel): STATUS_CHOICES = [ ('draft', 'Draft'), ('pending', 'Pending'), ('paid', 'Paid'), ('void', 'Void'), ('uncollectible', 'Uncollectible'), ] invoice_number = models.CharField(max_length=50, unique=True) subscription = models.ForeignKey('auth.Subscription', ...) status = models.CharField(max_length=20, choices=STATUS_CHOICES) subtotal = models.DecimalField(...) tax = models.DecimalField(...) total = models.DecimalField(...) currency = models.CharField(max_length=3, default='USD') due_date = models.DateField() line_items = models.JSONField(default=list) ``` ### Payment Model ```python class Payment(AccountBaseModel): STATUS_CHOICES = [ ('pending', 'Pending'), ('pending_approval', 'Pending Approval'), ('succeeded', 'Succeeded'), ('failed', 'Failed'), ('refunded', 'Refunded'), ] PAYMENT_METHOD_CHOICES = [ ('stripe', 'Stripe'), ('paypal', 'PayPal'), ('bank_transfer', 'Bank Transfer'), ('manual', 'Manual'), ] invoice = models.ForeignKey('Invoice', ...) amount = models.DecimalField(...) currency = models.CharField(max_length=3) payment_method = models.CharField(choices=PAYMENT_METHOD_CHOICES) status = models.CharField(choices=STATUS_CHOICES) stripe_payment_intent_id = models.CharField(...) paypal_order_id = models.CharField(...) manual_reference = models.CharField(..., unique=True) ``` ### WebhookEvent Model ```python class WebhookEvent(models.Model): """Audit trail for webhook processing""" PROVIDER_CHOICES = [ ('stripe', 'Stripe'), ('paypal', 'PayPal'), ] provider = models.CharField(choices=PROVIDER_CHOICES) event_id = models.CharField(max_length=255) event_type = models.CharField(max_length=100) payload = models.JSONField() status = models.CharField() # 'pending', 'processed', 'failed' processed_at = models.DateTimeField(null=True) error_message = models.TextField(blank=True) ``` --- ## Security Features ### Implemented Security Measures 1. **Webhook Signature Verification** - Stripe: `stripe.Webhook.construct_event()` with signing secret - PayPal: `verify_webhook_signature()` API call 2. **Idempotency** - `WebhookEvent` model tracks processed events - Duplicate detection before processing 3. **Amount Validation** - PayPal capture validates amount matches expected - Prevents manipulation attacks 4. **Manual Reference Uniqueness** - Database constraint prevents duplicate bank transfer references - Prevents double submission 5. **CSRF Protection** - Webhook endpoints exempt (external callers) - All other endpoints protected 6. **Authentication** - Payment endpoints require `IsAuthenticatedAndActive` - Config endpoints allow `AllowAny` (public keys only) --- ## Admin Operations ### Django Admin Features **Location:** Django Admin > Billing - **Invoices:** View, filter, download PDF - **Payments:** View, approve/reject manual payments - **Credit Transactions:** Audit trail - **Credit Packages:** Manage packages ### Manual Payment Approval ``` 1. Admin navigates to Payments in Django Admin 2. Filter by status='pending_approval' 3. Review payment details and proof 4. Click "Approve" or "Reject" action 5. System automatically: - Updates payment status - Marks invoice paid (if approved) - Activates account (if approved) - Adds credits (if approved) - Sends email notification ``` --- ## Configuration ### Environment Variables ```bash # Stripe STRIPE_SECRET_KEY=sk_... STRIPE_PUBLISHABLE_KEY=pk_... STRIPE_WEBHOOK_SECRET=whsec_... # PayPal PAYPAL_CLIENT_ID=... PAYPAL_CLIENT_SECRET=... PAYPAL_WEBHOOK_ID=... PAYPAL_MODE=sandbox|live # General DEFAULT_CURRENCY=USD ``` ### IntegrationProvider Setup Payment gateways configured via `IntegrationProvider` model in Django Admin: 1. **Stripe Provider:** - Name: "Stripe" - Provider Type: "stripe" - Credentials: `{"secret_key": "...", "publishable_key": "...", "webhook_secret": "..."}` 2. **PayPal Provider:** - Name: "PayPal" - Provider Type: "paypal" - Credentials: `{"client_id": "...", "client_secret": "...", "webhook_id": "..."}` --- ## Troubleshooting ### Common Issues | Issue | Cause | Solution | |-------|-------|----------| | "Stripe not configured" | Missing IntegrationProvider | Add Stripe provider in admin | | "PayPal not configured" | Missing IntegrationProvider | Add PayPal provider in admin | | PayPal shown for PK users | Country not passed correctly | Ensure `billing_country` saved on account | | Duplicate payments | Webhook retry without idempotency | Check `WebhookEvent` for duplicates | | PDF download fails | Missing `reportlab` | Run `pip install reportlab` | ### Debug Logging Enable billing debug logs: ```python # settings.py LOGGING = { 'loggers': { 'igny8_core.business.billing': { 'level': 'DEBUG', }, }, } ``` --- ## File Reference ### Backend Files | File | Description | |------|-------------| | `billing/views/stripe_views.py` | Stripe API endpoints | | `billing/views/paypal_views.py` | PayPal API endpoints | | `billing/views/refund_views.py` | Refund processing | | `billing/services/stripe_service.py` | Stripe service layer | | `billing/services/paypal_service.py` | PayPal service layer | | `billing/services/invoice_service.py` | Invoice operations | | `billing/services/payment_service.py` | Payment operations | | `billing/services/pdf_service.py` | PDF generation | | `billing/services/email_service.py` | Email notifications | | `billing/models.py` | Billing models | | `billing/urls.py` | URL routing | ### Frontend Files | File | Description | |------|-------------| | `services/billing.api.ts` | API client functions | | `pages/account/PlansAndBillingPage.tsx` | Main billing page | | `components/billing/PendingPaymentView.tsx` | New user payment | | `components/billing/BankTransferForm.tsx` | Bank transfer form | | `components/billing/PayInvoiceModal.tsx` | Invoice payment modal | | `components/billing/PaymentGatewaySelector.tsx` | Gateway selection | | `components/billing/PendingPaymentBanner.tsx` | Payment alert banner | --- *Document generated from production codebase - January 8, 2026*