Skip to main content

Django-native integration for Iyzico payment gateway - Turkey's leading payment solution with PCI DSS compliance

Project description

django-iyzico

Django integration for Iyzico payment gateway - Turkey's leading payment solution

Python Version Django Version License Tests Coverage Version

Note: This is an unofficial, community-maintained package and is not endorsed by or affiliated with Iyzico. For the official Iyzico Python SDK, please visit iyzipay-python.

django-iyzico provides a complete Django-native integration for the Iyzico payment gateway, designed specifically for the Turkish market. Reduce integration time from days to hours with a secure, well-tested, production-ready solution.

๐ŸŒŸ Features

Core Features

  • โœ… Payment Processing - Direct payments and 3D Secure support
  • โœ… Subscription Payments - Recurring billing with automated lifecycle management
  • โœ… Installment Payments - Full installment support with BIN-based options
  • โœ… Multi-Currency - Support for TRY, USD, EUR, GBP with conversion
  • โœ… PCI DSS Compliant - Secure card data handling (never stores full card numbers)
  • โœ… Refund Processing - Full and partial refunds
  • โœ… Django Admin - Professional interface with color-coded statuses
  • โœ… Webhook Handling - Real-time payment status updates
  • โœ… Signal System - Event-driven architecture (20 signals)
  • โœ… Celery Integration - Automated subscription billing and task processing
  • โœ… Management Commands - Sync and cleanup utilities
  • โœ… Type Hints - Full type coverage for IDE support
  • โœ… Well Tested - 662+ tests, 95%+ coverage across all modules
  • โœ… Monitoring - Structured logging, metrics, and alerting

Optional Features

  • ๐Ÿ”Œ Django REST Framework - Optional API support
  • ๐Ÿ”ง Advanced Utilities - Currency conversion, installment calculation, basket ID generator

๐Ÿ“ฆ Installation

pip install django-iyzico

Requirements

  • Python 3.12+
  • Django 4.2+ (supports 4.2 LTS, 5.2, 6.0)
  • iyzipay >= 1.0.45

๐Ÿš€ Quick Start

1. Add to INSTALLED_APPS

# settings.py
INSTALLED_APPS = [
    ...
    'django_iyzico',
]

2. Configure Settings

# settings.py

# Required settings
IYZICO_API_KEY = 'your-api-key'
IYZICO_SECRET_KEY = 'your-secret-key'
IYZICO_BASE_URL = 'https://sandbox-api.iyzipay.com'  # Sandbox
# IYZICO_BASE_URL = 'https://api.iyzipay.com'  # Production

# Optional settings (with defaults)
IYZICO_LOCALE = 'tr'  # Default locale
IYZICO_CURRENCY = 'TRY'  # Default currency

# Optional webhook security
IYZICO_WEBHOOK_SECRET = 'your-webhook-secret'  # For signature validation
IYZICO_WEBHOOK_ALLOWED_IPS = ['1.2.3.4', '5.6.7.0/24']  # IP whitelist with CIDR

3. Create Your Payment Model

# models.py
from django.db import models
from django_iyzico.models import AbstractIyzicoPayment

class Order(AbstractIyzicoPayment):
    """Your order model extending Iyzico payment."""

    user = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    product = models.CharField(max_length=200)

    class Meta:
        db_table = 'orders'
        ordering = ['-created_at']

4. Run Migrations

python manage.py makemigrations
python manage.py migrate

5. Include URLs

# urls.py
from django.urls import path, include

urlpatterns = [
    path('payments/', include('django_iyzico.urls')),
    ...
]

6. Process a Payment

# views.py
from decimal import Decimal
from django_iyzico.client import IyzicoClient
from .models import Order

def checkout(request):
    # Create order
    order = Order.objects.create(
        user=request.user,
        product="Premium Subscription",
        amount=Decimal("99.00"),
        conversation_id="ORDER-12345"
    )

    # Process payment
    client = IyzicoClient()

    payment_data = {
        'price': '99.00',
        'paidPrice': '99.00',
        'currency': 'TRY',
        'basketId': 'BASKET-12345',
        'paymentCard': {
            'cardHolderName': request.POST['card_holder'],
            'cardNumber': request.POST['card_number'],
            'expireMonth': request.POST['expire_month'],
            'expireYear': request.POST['expire_year'],
            'cvc': request.POST['cvc'],
        },
        'buyer': {
            'id': str(request.user.id),
            'name': request.user.first_name,
            'surname': request.user.last_name,
            'email': request.user.email,
            'identityNumber': '11111111111',
            'registrationAddress': 'Address here',
            'city': 'Istanbul',
            'country': 'Turkey',
            'zipCode': '34000',
        },
    }

    try:
        response = client.create_payment(payment_data)

        if response.is_successful():
            # Update order
            order.update_from_response(response)
            return redirect('order_success', order_id=order.id)
        else:
            messages.error(request, response.error_message)
            return redirect('checkout')

    except PaymentError as e:
        messages.error(request, "Payment failed. Please try again.")
        return redirect('checkout')

7. Process Subscription Payments (v0.2.0+)

from django_iyzico.subscription_models import SubscriptionPlan, Subscription
from django_iyzico.subscription_manager import SubscriptionManager

# Create a subscription plan
plan = SubscriptionPlan.objects.create(
    name="Premium Monthly",
    price=Decimal("99.00"),
    currency="TRY",
    billing_interval="MONTHLY",
    billing_period=1,
    trial_days=7
)

# Subscribe a user
manager = SubscriptionManager()
subscription = manager.create_subscription(
    plan=plan,
    user=request.user,
    payment_method={
        'cardHolderName': 'John Doe',
        'cardNumber': '5528790000000008',
        'expireMonth': '12',
        'expireYear': '2030',
        'cvc': '123',
    }
)

# Subscription automatically bills every month
# See docs/SUBSCRIPTION_GUIDE.md for complete guide

8. Use Installment Payments (v0.2.0+)

from django_iyzico.installment_client import InstallmentClient

# Get installment options for a card
client = InstallmentClient()
options = client.get_installment_info(
    bin_number='552879',  # First 6 digits of card
    price=Decimal('1000.00')
)

# Display installment options to user
for option in options:
    print(f"{option.installment_count} installments: {option.installment_price}/month")
    print(f"Total: {option.total_price} (Rate: {option.installment_rate}%)")

# Process payment with installments
payment_data['installment'] = 3  # 3 installments
response = client.create_payment(payment_data)

# See docs/INSTALLMENT_GUIDE.md for complete guide

9. Multi-Currency Support (v0.2.0+)

from django_iyzico.currency import format_amount, CurrencyConverter

# Create payment in any supported currency
order = Order.objects.create(
    amount=Decimal("100.00"),
    currency='USD'  # TRY, USD, EUR, or GBP
)

# Format amount with currency symbol
formatted = order.get_formatted_amount()  # "$100.00"

# Convert between currencies
converter = CurrencyConverter()
try_amount = order.convert_to_currency('TRY')
print(f"${order.amount} USD = โ‚บ{try_amount} TRY")

# See docs/CURRENCY_GUIDE.md for complete guide

๐ŸŽจ Django Admin Integration

# admin.py
from django.contrib import admin
from django_iyzico.admin import IyzicoPaymentAdminMixin
from .models import Order

@admin.register(Order)
class OrderAdmin(IyzicoPaymentAdminMixin, admin.ModelAdmin):
    list_display = IyzicoPaymentAdminMixin.list_display + ['user', 'product']

    # All payment admin features included:
    # - Color-coded status badges
    # - Advanced filtering
    # - Bulk refund action
    # - CSV export
    # - Delete protection

๐Ÿ“ก Signal Handling

django-iyzico provides 20 signals for payment, subscription, and monitoring events:

Payment Signals (8 signals)

# signals.py
from django.dispatch import receiver
from django_iyzico.signals import (
    payment_completed, payment_failed, payment_refunded,
    threeds_completed, webhook_received
)

@receiver(payment_completed)
def on_payment_success(sender, instance, **kwargs):
    """Handle successful payment."""
    # Update user subscription
    instance.user.activate_premium()

    # Send confirmation email
    send_email(instance.buyer_email, "Payment Confirmed")

    # Log for analytics
    track_event('payment_success', amount=instance.amount)

@receiver(payment_failed)
def on_payment_failed(sender, instance, **kwargs):
    """Handle failed payment."""
    # Log failure
    logger.error(f"Payment failed: {instance.error_message}")

    # Notify user
    send_email(instance.buyer_email, "Payment Failed")

Subscription Signals (9 signals - v0.2.0+)

from django_iyzico.subscription_signals import (
    subscription_created, subscription_activated,
    subscription_cancelled, subscription_payment_succeeded,
    subscription_payment_failed
)

@receiver(subscription_activated)
def on_subscription_activated(sender, subscription, **kwargs):
    """Handle subscription activation."""
    # Grant access to premium features
    subscription.user.grant_premium_access()

    # Send welcome email
    send_email(subscription.user.email, "Welcome to Premium!")

@receiver(subscription_payment_failed)
def on_subscription_payment_failed(sender, subscription, payment, **kwargs):
    """Handle failed subscription payment."""
    # Notify user
    send_email(subscription.user.email, "Payment Failed - Please Update Card")

    # Log for retry
    logger.warning(f"Subscription {subscription.id} payment failed")

Monitoring Signals (3 signals - v0.2.0+)

from django_iyzico.signals import (
    payment_alert, double_billing_prevented, high_failure_rate_detected
)

@receiver(payment_alert)
def on_payment_alert(sender, alert_type, message, severity, **kwargs):
    """Handle payment system alerts."""
    if severity == 'critical':
        notify_ops_team(alert_type, message)

@receiver(double_billing_prevented)
def on_double_billing_prevented(sender, subscription_id, **kwargs):
    """Log prevented double billing attempts."""
    logger.info(f"Double billing prevented for subscription {subscription_id}")

@receiver(high_failure_rate_detected)
def on_high_failure_rate(sender, failure_rate, threshold, **kwargs):
    """Alert on high payment failure rates."""
    alert_ops(f"Payment failure rate {failure_rate:.1%} exceeds threshold {threshold:.1%}")

๐Ÿ”„ Webhook Handling

Webhooks are automatically handled at /payments/webhook/. Configure your Iyzico merchant panel to send webhooks to:

https://yourdomain.com/payments/webhook/

For enhanced security, configure webhook validation:

# settings.py
IYZICO_WEBHOOK_SECRET = 'your-webhook-secret'  # HMAC signature validation
IYZICO_WEBHOOK_ALLOWED_IPS = ['1.2.3.4']  # IP whitelist

๐Ÿ’ฐ Refund Processing

# Process a refund
from .models import Order

order = Order.objects.get(id=order_id)

# Full refund
response = order.process_refund()

# Partial refund
response = order.process_refund(
    amount=Decimal("50.00"),
    reason="Customer request"
)

if response.is_successful():
    # Refund processed
    # Status automatically updated
    # Signal automatically triggered
    pass

๐Ÿ› ๏ธ Management Commands

Sync Payment Statuses

# Sync payments from last 7 days
python manage.py sync_iyzico_payments --model myapp.models.Order --days 7

# Dry run (see what would be updated)
python manage.py sync_iyzico_payments --model myapp.models.Order --dry-run

# Filter by status
python manage.py sync_iyzico_payments --model myapp.models.Order --status pending

Clean Up Old Payments

# Delete payments older than 365 days
python manage.py cleanup_old_payments --model myapp.models.Order --days 365

# Keep successful payments longer
python manage.py cleanup_old_payments \
    --model myapp.models.Order \
    --days 365 \
    --keep-successful 730

# Export before deleting
python manage.py cleanup_old_payments \
    --model myapp.models.Order \
    --export /backup/payments.csv \
    --days 365

๐Ÿ”Œ Django REST Framework (Optional)

If you have DRF installed, you can use the optional API support:

# urls.py
from rest_framework.routers import DefaultRouter
from django_iyzico.viewsets import IyzicoPaymentViewSet
from .models import Order

router = DefaultRouter()

# Configure viewset with your model
class OrderPaymentViewSet(IyzicoPaymentViewSet):
    queryset = Order.objects.all()

router.register('payments', OrderPaymentViewSet, basename='payment')

urlpatterns = [
    path('api/', include(router.urls)),
]

API Endpoints:

  • GET /api/payments/ - List all payments
  • GET /api/payments/{id}/ - Retrieve payment details
  • GET /api/payments/successful/ - List successful payments
  • GET /api/payments/failed/ - List failed payments
  • GET /api/payments/stats/ - Payment statistics

๐Ÿ”’ Security

PCI DSS Compliance

django-iyzico is designed to be PCI DSS Level 1 compliant:

  • โœ… Never stores full card numbers - Only last 4 digits
  • โœ… Never stores CVC/CVV codes
  • โœ… Automatic log sanitization - No sensitive data in logs
  • โœ… Secure card data masking
  • โœ… Input validation on all endpoints

Webhook Security

  • โœ… HMAC-SHA256 signature validation
  • โœ… IP whitelisting with CIDR support
  • โœ… Constant-time comparison (timing attack prevention)
  • โœ… X-Forwarded-For header support

Best Practices

See SECURITY.md for complete security guidelines.

๐Ÿงช Testing

# Run all tests
pytest

# With coverage
pytest --cov=django_iyzico --cov-report=html

# Specific test file
pytest tests/test_client.py -v

Test Statistics:

  • 662+ test methods across 22 test files
  • 95%+ coverage across all modules
  • ~12,000 lines of test code
  • Comprehensive test suites for payments, subscriptions, installments, currency, and monitoring
  • 83+ security-critical tests

๐Ÿ”ง Troubleshooting

Common Issues and Solutions

1. Payment Fails with "INVALID_SIGNATURE" Error

Problem: Payment requests return an error about invalid signature.

Solution:

# Verify your API credentials are correct
# settings.py
IYZICO_API_KEY = 'your-correct-api-key'
IYZICO_SECRET_KEY = 'your-correct-secret-key'
IYZICO_BASE_URL = 'https://sandbox-api.iyzipay.com'  # For testing

# Check that credentials match your Iyzico merchant panel
# Production credentials differ from sandbox credentials

2. Webhook Not Receiving Updates

Problem: Payments succeed but webhooks don't trigger.

Solution:

# 1. Ensure webhook URL is publicly accessible
IYZICO_WEBHOOK_SECRET = 'your-webhook-secret'

# 2. Configure webhook URL in Iyzico merchant panel:
# https://yourdomain.com/payments/webhook/

# 3. Check webhook logs
import logging
logger = logging.getLogger('django_iyzico')
logger.setLevel(logging.DEBUG)

# 4. Verify IP whitelist (if configured)
IYZICO_WEBHOOK_ALLOWED_IPS = []  # Allow all IPs for testing

# 5. Test webhook locally with ngrok:
# ngrok http 8000
# Use ngrok URL in Iyzico panel

3. "Payment ID already exists" Error

Problem: Duplicate payment_id constraint violation.

Solution:

# Use unique conversation_id for each payment attempt
import uuid

order = Order.objects.create(
    conversation_id=f"ORDER-{uuid.uuid4()}",  # Always unique
    amount=Decimal("99.00")
)

# Or use the utility function
from django_iyzico.utils import generate_basket_id
basket_id = generate_basket_id()  # Returns UUID-based ID

4. Card Data Not Saving

Problem: card_last_four_digits is always None.

Solution:

# Store card data before sending to Iyzico
payment_data = {
    'paymentCard': {
        'cardNumber': '5528790000000008',
        # ... other fields
    }
}

# Extract and store card info
order.mask_and_store_card_data(payment_data)

# Then process payment
response = client.create_payment(...)

5. 3D Secure Callback Fails

Problem: 3DS callback returns 404 or doesn't update payment.

Solution:

# 1. Verify URLs are included in your project
# urls.py
urlpatterns = [
    path('payments/', include('django_iyzico.urls')),  # Required
]

# 2. Check callback URL configuration
IYZICO_CALLBACK_URL = 'https://yourdomain.com/payments/callback/'

# 3. Ensure callback URL is accessible (not behind auth)
# The view has @csrf_exempt decorator by default

# 4. Check payment token in callback
# Token should be in GET parameters: ?token=xxx

6. Refund Fails with "INSUFFICIENT_FUNDS"

Problem: Refund requests fail even though payment was successful.

Solution:

# 1. Check payment status
if order.can_be_refunded():
    # Payment must be SUCCESS status
    response = order.process_refund()

# 2. For partial refunds, ensure amount is valid
if order.amount >= Decimal("50.00"):
    response = order.process_refund(amount=Decimal("50.00"))

# 3. Check Iyzico merchant account balance
# Refunds require sufficient balance in merchant account

# 4. Wait time: Allow 24 hours after payment before refund

7. Admin Shows Wrong Payment Status

Problem: Admin displays incorrect status or outdated data.

Solution:

# Sync payment statuses with Iyzico API
python manage.py sync_iyzico_payments --model myapp.Order --days 7

# Check for specific payment
python manage.py sync_iyzico_payments --model myapp.Order --payment-id 12345

# Use --dry-run to see what would be updated
python manage.py sync_iyzico_payments --model myapp.Order --dry-run

8. Migration Errors

Problem: Errors when running makemigrations or migrate.

Solution:

# 1. Ensure django_iyzico is in INSTALLED_APPS
# settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    # ...
    'django_iyzico',  # Add this
    'myapp',  # Your app with Order model
]

# 2. Create migrations for your model
python manage.py makemigrations myapp

# 3. Apply migrations
python manage.py migrate

# 4. If you get conflicts, try:
python manage.py makemigrations --merge

9. Test Card Numbers Not Working

Problem: Sandbox test cards are being rejected.

Solution:

# Use Iyzico's official test cards:

# Successful payment test card:
{
    'cardNumber': '5528790000000008',
    'cardHolderName': 'John Doe',
    'expireMonth': '12',
    'expireYear': '2030',
    'cvc': '123'
}

# 3D Secure test card (OTP: 123456):
{
    'cardNumber': '5528790000000008',
    'cardHolderName': 'John Doe',
    'expireMonth': '12',
    'expireYear': '2030',
    'cvc': '123'
}

# Ensure you're using SANDBOX_BASE_URL
IYZICO_BASE_URL = 'https://sandbox-api.iyzipay.com'

10. High Response Times

Problem: Payment processing is slow.

Solution:

# 1. Enable database connection pooling
# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'CONN_MAX_AGE': 600,  # Connection pooling
    }
}

# 2. Use select_related for foreign keys
orders = Order.objects.select_related('user').all()

# 3. Add database indexes (already included in AbstractIyzicoPayment)
# Check with:
# python manage.py sqlmigrate myapp 0001

# 4. Cache Iyzico settings
from django.core.cache import cache
# Settings are auto-cached in IyzicoClient

# 5. Use async views for I/O-bound operations (Django 4.1+)
from django.views.decorators.http import require_http_methods

Debug Mode

Enable detailed logging for troubleshooting:

# settings.py
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django_iyzico': {
            'handlers': ['console'],
            'level': 'DEBUG',  # Shows all API calls
            'propagate': False,
        },
    },
}

Getting Help

If you're still experiencing issues:

  1. Check the GitHub Issues for similar problems
  2. Review the SECURITY.md for security-related questions
  3. Enable DEBUG logging and check the output
  4. Create a new issue with:
    • Django version
    • Python version
    • django-iyzico version
    • Error message and full traceback
    • Minimal code to reproduce the issue

๐Ÿ“š Documentation

Core Documentation

Feature Guides (v0.2.0+)

๐Ÿค Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

Development Setup

# Clone repository
git clone https://github.com/aladagemre/django-iyzico.git
cd django-iyzico

# Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install in development mode
pip install -e ".[dev]"

# Run tests
pytest

# Format code
black django_iyzico tests
isort django_iyzico tests

# Run linters
flake8 django_iyzico
mypy django_iyzico

๐Ÿ“Š Project Status

Phase Status Features
Milestone 1 โœ… Complete Core payment processing, admin, refunds
Milestone 2 โœ… Complete Subscription payments with Celery
Milestone 3 โœ… Complete Installment payments
Milestone 4 โœ… Complete Multi-currency support
Milestone 5 โœ… Complete v0.2.0 Release with monitoring & CI/CD

๐Ÿ—บ๏ธ Roadmap

v0.1.0-beta (Released - December 2025)

  • โœ… Core payment processing (direct and 3D Secure)
  • โœ… Admin interface with advanced features
  • โœ… Refund processing (full and partial)
  • โœ… Webhook handling with security
  • โœ… Management commands
  • โœ… 95% test coverage
  • โœ… PCI DSS compliance

v0.2.0 (Released - December 2025)

  • โœ… Subscription payments - Recurring billing with automated lifecycle
  • โœ… Installment support - BIN-based installment options and processing
  • โœ… Multi-currency support - TRY, USD, EUR, GBP with conversion
  • โœ… Celery integration - Automated subscription billing tasks
  • โœ… Monitoring module - Structured logging, metrics, and alerting
  • โœ… 20 lifecycle signals - Payment, subscription, and monitoring events
  • โœ… 662+ comprehensive tests - 95%+ coverage maintained
  • โœ… CI/CD workflows - GitHub Actions for testing and publishing
  • โœ… DevContainer support - VS Code development environment
  • โœ… Complete example project - Full Django app with all features

v0.3.0 (Planned)

  • Payment tokenization
  • Split payments for marketplaces
  • Additional payment methods (bank transfer, etc.)
  • Enhanced reporting and analytics
  • Webhook retry mechanism

๐Ÿ“ License

MIT License - See LICENSE for details.

๐Ÿ™ Credits

Built on top of the official iyzipay-python SDK.

๐Ÿ’ฌ Support

โญ Show Your Support

If django-iyzico helps your project, please give it a star on GitHub!


Author: Emre Aladag (@aladagemre) Version: 0.2.0 Status: โœ… Production-Ready Last Updated: December 18, 2025

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_iyzico-0.2.2.tar.gz (120.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_iyzico-0.2.2-py3-none-any.whl (115.0 kB view details)

Uploaded Python 3

File details

Details for the file django_iyzico-0.2.2.tar.gz.

File metadata

  • Download URL: django_iyzico-0.2.2.tar.gz
  • Upload date:
  • Size: 120.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for django_iyzico-0.2.2.tar.gz
Algorithm Hash digest
SHA256 78539ec6d4043b8daef825afcc5c009779622f288e2cf60ca9b07d70952006c4
MD5 717ea6e0943280bffe348ffca6456b8c
BLAKE2b-256 7503b5082bf547eb088a55455a9ea74292a5daef1da4bcf51bb786a43cc00df9

See more details on using hashes here.

File details

Details for the file django_iyzico-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: django_iyzico-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 115.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for django_iyzico-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 6b59e93a3c3a6b2e067ba4b031defb794f44c57c188841537a90900360281f1f
MD5 ec9f4608f0a223bca3303dde06959ad5
BLAKE2b-256 dc5ebe6927e96b52ee6f5920d0e18028a057d363a8fe4710abe3b0a05702fd51

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page