Files
igny8/docs/90-REFERENCE/PAYMENT-SYSTEM.md
IGNY8 VPS (Salman) 257b6817f1 Version 1.9.0
2026-01-20 07:58:48 +00:00

21 KiB

Payment System Documentation

Version: 2.0.0
Last Updated: January 20, 2026
Status: Production Ready

Complete Billing Reference: For comprehensive billing documentation including the two-pool credit system and renewal workflows, see BILLING-PAYMENTS-COMPLETE.md

This document provides payment gateway implementation details for IGNY8.


Table of Contents

  1. System Overview
  2. Payment Entry Points
  3. Backend Architecture
  4. Frontend Architecture
  5. Payment Flows
  6. Country-Based Payment Rules
  7. Webhook Processing
  8. Models Reference
  9. 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
// 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:

// 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

// 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

// 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:

# 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:

is_valid = service.verify_webhook_signature(...)
if not is_valid:
    return Response({'error': 'Invalid signature'}, status=400)

Models Reference

Invoice Model

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

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

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

# 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:

# 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