Django Tamara Payment Gateway
A professional Django package for integrating Tamara - the leading Buy Now Pay Later (BNPL) payment solution in the Middle East. Supports Saudi Arabia, UAE, Kuwait, Bahrain, Qatar, and Oman.
Features
- ✅ Full Tamara Online Checkout flow
- ✅ Payment Types lookup
- ✅ Create Checkout Sessions
- ✅ Authorise / Capture / Cancel / Refund orders
- ✅ Webhook management (register, list, update, delete)
- ✅ Sandbox & Production environments
- ✅ Multi-currency support (SAR, AED, KWD, BHD, QAR, OMR)
- ✅ Multi-country support (SA, AE, KW, BH, QA, OM)
- ✅ In-store checkout support
- ✅ Requests HTTP client (no raw cURL)
- ✅ Configurable URL prefix & middleware
- ✅ Transaction logging model
- ✅ Django 4.2, 5.0 & 5.1 compatible
- ✅ Python 3.9+
Requirements
| Django | Python | Package Version |
|---|---|---|
| 4.2.x | 3.9+ | ^2.0 |
| 5.0.x | 3.10+ | ^2.0 |
| 5.1.x | 3.10+ | ^2.0 |
| 5.2.x | 3.10+ | ^2.0 |
| 6.0.x | 3.12+ | ^2.0 |
Installation
pip install aghfatehi-django-tamara
Configuration
1. Add to INSTALLED_APPS
# settings.py
INSTALLED_APPS = [
...
'tamara',
]
2. Environment / Settings Variables
# settings.py
# ─── Tamara Payment Gateway Settings ──────────────────────────────
TAMARA_SANDBOX_MODE = True
# bool | Sandbox mode (testing) when True, Production mode when False
TAMARA_API_TOKEN = "your-api-token-here"
# string | Your Tamara API token from Tamara dashboard
TAMARA_COUNTRY_CODE = "SA"
# string (2 chars) | Country code
# SA = Saudi Arabia | AE = UAE | KW = Kuwait | BH = Bahrain | QA = Qatar | OM = Oman
TAMARA_CURRENCY = "SAR"
# string (3 chars) | Currency code
# SAR = Saudi Riyal | AED = UAE Dirham | KWD = Kuwaiti Dinar | BHD = Bahraini Dinar | QAR = Qatari Riyal | OMR = Omani Riyal
TAMARA_INSTALMENTS = 3
# int | Number of instalments (3, 4, or 6)
TAMARA_PAYMENT_TYPE = "PAY_BY_INSTALMENTS"
# string | Payment type - "PAY_BY_INSTALMENTS" or "PAY_NEXT_MONTH" or "SINGLE_PAYMENT"
TAMARA_LOCALE = "en_US"
# string | Locale - "en_US" or "ar_SA"
TAMARA_ROUTE_PREFIX = "tamara"
# string | URL prefix for all Tamara routes
3. Include URLs
# urls.py
from django.urls import include, path
urlpatterns = [
...
path('tamara/', include('tamara.urls')),
]
4. Run Migrations
python manage.py migrate tamara
Usage
Quick Start - Frontend Checkout
from tamara.client import client
# Get available payment types
types = client.get_payment_types('SA', 'SAR', 500)
# Create a checkout session
response = client.create_checkout({
'total_amount': {'amount': 500, 'currency': 'SAR'},
'order_reference_id': 'ORD-' + str(int(__import__('time').time())),
'order_number': 'INV-2024-001',
'consumer': {
'email': 'customer@example.com',
'first_name': 'Ahmed',
'last_name': 'Ali',
'phone_number': '500000000',
},
'country_code': 'SA',
'merchant_url': {
'success': 'https://example.com/tamara/callback',
'failure': 'https://example.com/tamara/failure',
'cancel': 'https://example.com/tamara/cancel',
'notification': 'https://example.com/tamara/webhook',
},
})
# Redirect customer to Tamara checkout
if 'checkout_url' in response:
# return redirect(response['checkout_url'])
print(f"Redirect to: {response['checkout_url']}")
Using Routes
The package registers these routes under the configured prefix (/tamara by default):
| Method | URI | Name | Description |
|---|---|---|---|
| GET | /tamara/payment/types |
tamara:payment_types |
Get eligible payment types |
| POST | /tamara/pay |
tamara:pay |
Initiate checkout |
| ANY | /tamara/callback |
tamara:callback |
Payment callback |
| GET | /tamara/cancel |
tamara:cancel |
Cancel handler |
| GET | /tamara/failure |
tamara:failure |
Failure handler |
| POST | /tamara/webhook |
tamara:webhook |
Webhook receiver |
| POST | /tamara/authorise |
tamara:authorise |
Authorise order |
API Methods
from tamara.client import client
# Payment Types
types = client.get_payment_types('SA', 'SAR', 500, '500000000')
# Checkout
checkout = client.create_checkout(data)
# Order Management
order = client.get_order('order-id-here')
order = client.get_order_by_reference_id('ref-id-here')
# Authorise / Capture / Cancel / Refund
authorised = client.authorise_order('order-id')
captured = client.capture_order('order-id', {'amount': 500})
cancelled = client.cancel_order('order-id', {'reason': 'out_of_stock'})
refunded = client.refund_order('order-id', 500, 'SAR', 'Refund comment')
# Webhook Management
webhook = client.webhook_register(
'https://example.com/webhook',
['order_approved', 'order_declined', 'order_authorised', 'order_captured', 'order_refunded'],
)
webhook_list = client.webhook_list()
webhook_detail = client.webhook_get('webhook-id')
client.webhook_delete('webhook-id')
client.webhook_update('webhook-id', 'https://example.com/webhook', ['order_approved'])
Handling Webhooks
The webhook endpoint logs all incoming events. Extend the view or listen to the log to implement your business logic:
# views.py (custom webhook handler)
import json
import logging
from django.http import JsonResponse
from django.views import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
logger = logging.getLogger(__name__)
@method_decorator(csrf_exempt, name='dispatch')
class CustomWebhookView(View):
def post(self, request):
payload = json.loads(request.body)
event = payload.get('event_type')
order_id = payload.get('order_id')
status = payload.get('status')
if event == 'order_approved':
# Mark order as approved
pass
elif event == 'order_captured':
# Fulfill the order
pass
elif event == 'order_refunded':
# Process refund
pass
return JsonResponse({'success': True})
Development
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Lint
ruff check src/ tests/
Changelog
See CHANGELOG for recent changes.
Security
If you discover security issues, please email fathi.a.n2002@gmail.com instead of using the issue tracker.
License
This package is open-sourced software licensed under the MIT license.
Support
- Issues: GitHub Issues
- Tamara Docs: https://docs.tamara.co
- Author: AL-AGHBARI Fatehi (fathi.a.n2002@gmail.com)
Countries & Currencies
| Country | Code | Currency | Code |
|---|---|---|---|
| Saudi Arabia | SA | Riyal | SAR |
| UAE | AE | Dirham | AED |
| Kuwait | KW | Dinar | KWD |
| Bahrain | BH | Dinar | BHD |
| Qatar | QA | Riyal | QAR |
| Oman | OM | Riyal | OMR |
Metadata
Release files for aghfatehi-django-tamara 2.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| aghfatehi_django_tamara-2.0.1.tar.gz | 11.6 kB | Without provenance | Details for aghfatehi_django_tamara-2.0.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| aghfatehi_django_tamara-2.0.1-py3-none-any.whl | Python 3 | none | any | Details for aghfatehi_django_tamara-2.0.1-py3-none-any.whl |
Total release size: 24.2 kB
Release files / aghfatehi_django_tamara-2.0.1.tar.gz
| Download URL | aghfatehi_django_tamara-2.0.1.tar.gz |
|---|---|
| Size | 11.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a4394d2520b876607cfcddd6a2b2fa7460c560d81cb922c6a9b69116a6a57eb9
|
|
BLAKE2b-256 checksum How to use checksums |
e82d26bfaaf3e914ea1361f2c9c717a05936daec3ddafc053388faf7f20fd7f3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / aghfatehi_django_tamara-2.0.1-py3-none-any.whl
| Download URL | aghfatehi_django_tamara-2.0.1-py3-none-any.whl |
|---|---|
| Size | 12.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
18d79e01d44a0914cea64ceed12e43665c9687b7e7d482e3ff8ffd2ca70ba243
|
|
BLAKE2b-256 checksum How to use checksums |
79edb19435119203c593a2c81bb3be666eb22f1e8888af1511245b7907f55771
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Security for aghfatehi-django-tamara 2.0.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.