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
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 paymentsGET /api/payments/{id}/- Retrieve payment detailsGET /api/payments/successful/- List successful paymentsGET /api/payments/failed/- List failed paymentsGET /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:
- Check the GitHub Issues for similar problems
- Review the SECURITY.md for security-related questions
- Enable DEBUG logging and check the output
- 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
- Changelog - Version history and migration guide
- Security Policy - Security features and best practices
- Contributing - Development guidelines
- Development Roadmap - Project roadmap and milestones
Feature Guides (v0.2.0+)
- Subscription Guide - Complete guide to recurring billing (800+ lines)
- Installment Guide - Complete guide to installment payments (800+ lines)
- Currency Guide - Complete guide to multi-currency support (600+ lines)
- Release Notes v0.2.0 - Complete v0.2.0 release documentation
๐ค 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
- Issues: GitHub Issues
- Security: See SECURITY.md
โญ 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_iyzico-0.2.1.tar.gz.
File metadata
- Download URL: django_iyzico-0.2.1.tar.gz
- Upload date:
- Size: 118.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1198a6d20b6514f6b0d44b6b9e139c77d9df6c84749b026cd5d63855418a7957
|
|
| MD5 |
4a6cfed6b3f9aa40e3ac69cfdcac56f3
|
|
| BLAKE2b-256 |
45d80c19eeaf6324df574c7d62943e300d99b06abd2451b1ec2e1b454846c79f
|
File details
Details for the file django_iyzico-0.2.1-py3-none-any.whl.
File metadata
- Download URL: django_iyzico-0.2.1-py3-none-any.whl
- Upload date:
- Size: 113.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f9ff535583d04dc8a80ae11603021f49ce18fff67bb88115041a68039e6f46ce
|
|
| MD5 |
35b46cb0a60ec7584f2639e152becdbb
|
|
| BLAKE2b-256 |
baaf94784612798bda317bb98939c31a59b672a6cdb4fbb90378daaab73f6871
|