Django + ATH Móvil
Project description
django-athm
Django integration for ATH Móvil payments (Puerto Rico's mobile payment system).
See this README in spanish: README_ES.md
Main Purpose
Webhook-driven payment and refund synchronization. ATH Móvil sends definitive transaction data via webhooks, providing complete audit trails with fees, net amounts, and customer information.
Features
- Webhook handling with idempotency
- Transaction persistence with refunds and client records for complete audit trails
- Read-only Django Admin with refund actions and webhook management
- Django signals for payment lifecycle events (completed, cancelled, expired, refunded)
- Transaction reconciliation via the
athm_syncmanagement command - Optional payment button template tag with zero-dependency JavaScript for quick integration
Requirements
- Python 3.10 - 3.14
- Django 5.1 - 6.0
Installation
pip install django-athm
Add to your INSTALLED_APPS:
INSTALLED_APPS = [
# ...
"django_athm",
]
Add your ATH Móvil Business API tokens (find these in the mobile app's settings):
DJANGO_ATHM_PUBLIC_TOKEN = "your-public-token"
DJANGO_ATHM_PRIVATE_TOKEN = "your-private-token"
Include the URLs:
# urls.py
from django.urls import include, path
urlpatterns = [
# ...
path("athm/", include("django_athm.urls")),
]
Run migrations:
python manage.py migrate django_athm
Quick Start (using bundled templatetag)
1. Create a view with payment configuration
# views.py
from django.shortcuts import render
def checkout(request):
athm_config = {
"total": 25.00,
"subtotal": 23.36,
"tax": 1.64,
"metadata_1": "order-123",
"items": [
{"name": "Widget", "price": 23.36, "quantity": 1}
],
"success_url": "/order/complete/",
"failure_url": "/order/failed/",
}
return render(request, "checkout.html", {"ATHM_CONFIG": athm_config})
2. Add the payment button to your template
{% load django_athm %}
<h1>Checkout</h1>
{% athm_button ATHM_CONFIG %}
3. Handle payment completion with signals
# signals.py
from django.dispatch import receiver
from django_athm.signals import payment_completed
@receiver(payment_completed)
def handle_payment_completed(sender, payment, **kwargs):
# Update your order status, send confirmation email, etc.
print(f"Payment {payment.reference_number} completed for ${payment.total}")
Architecture
Webhook-Driven Synchronization
Webhooks provide definitive transaction data with idempotency guarantees:
ATH Móvil webhook -> Idempotent processing -> Payment/Refund sync -> Django signals
Optional Modal Payment Flow
For quick integration, use the included template tag:
- Initiate: User clicks button, backend creates payment via ATH Móvil API
- Confirm: User confirms payment in ATH Móvil app
- Authorize: Backend authorizes the confirmed payment
- Webhook: ATH Móvil sends completion event with final details
User clicks -> Backend creates -> User confirms -> Backend authorizes -> Webhook received
ATH Móvil payment (OPEN) in app (CONFIRM) payment (COMPLETED) (final details)
button
You can also build your own payment UI and use only the webhook synchronization features.
Webhooks
Installing Webhooks
Recommended: Use Django Admin (auto-detects your webhook URL):
- Navigate to ATH Móvil Webhook Events in the admin
- Click Install Webhooks button
- Verify the auto-detected URL (edit if needed)
- Click submit to register with ATH Móvil
Alternative: Management command
# Auto-detect from DJANGO_ATHM_WEBHOOK_URL setting
python manage.py install_webhook
# Or provide explicit URL
python manage.py install_webhook https://yourdomain.com/athm/webhook/
Transaction Reconciliation
Reconcile local records with ATH Movil's Transaction Report API to recover missed webhooks or backfill historical data:
# Sync transactions for a date range
python manage.py athm_sync --from-date 2025-01-01 --to-date 2025-01-31
# Preview changes without modifying database
python manage.py athm_sync --from-date 2025-01-01 --to-date 2025-01-31 --dry-run
Webhook Idempotency
All webhooks are processed idempotently using deterministic keys based on the event payload. Duplicate events are automatically detected and ignored.
Custom Webhook Views
If you need custom logic before/after webhook processing:
from django.views.decorators.csrf import csrf_exempt
from django_athm.views import process_webhook_request
@csrf_exempt
def my_custom_webhook(request):
# Pre-processing (logging, rate limiting, etc.)
log_webhook(request)
# Call django-athm handler (maintains idempotency)
response = process_webhook_request(request)
# Post-processing (notifications, analytics, etc.)
notify_team()
return response
Django Admin
The package provides a read-only admin interface:
- Payments: View all transactions, filter by status/date, bulk refund action
- Refunds: View refund records
- Clients: View customer records linked by phone number
- Webhook Events: View webhook history, reprocess failed events, install webhooks
All models are read-only to preserve data integrity - payments can only be refunded, not edited.
Optional Template Tag Configuration
The athm_button template tag is optional - you can build your own payment UI and use only the webhook features.
athm_config = {
# Required
"total": 25.00, # Payment amount (1.00 - 1500.00)
# Optional
"subtotal": 23.36, # Subtotal for display
"tax": 1.64, # Tax amount
"metadata_1": "order-123", # Custom field (max 40 chars)
"metadata_2": "customer-456",# Custom field (max 40 chars)
"items": [...], # List of item objects
"theme": "btn", # Button theme: btn, btn-dark, btn-light
"lang": "es", # Language: es, en
"success_url": "/thanks/", # Redirect on success (adds ?reference_number=...&ecommerce_id=...)
"failure_url": "/failed/", # Redirect on failure
}
Signals
Subscribe to payment lifecycle events:
from django_athm.signals import (
payment_completed, # Payment successful (webhook)
payment_cancelled, # Payment cancelled (webhook)
payment_expired, # Payment expired (webhook)
refund_sent, # Refund processed (webhook)
)
Development Setup
This project uses uv for package management.
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install dependencies
uv sync
# Run tests
DJANGO_SETTINGS_MODULE=tests.settings pytest --cov django_athm
# Run full test matrix
tox
# Run linting
tox -e lint
Legal
This project is not affiliated with or endorsed by Evertec, Inc. or ATH Móvil.
Dependencies
- athm-python - ATH Móvil API client
References
Feedback
Have suggestions or ideas for improving django-athm? We'd love to hear from you! Submit feedback.
License
MIT License - see LICENSE for details.
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_athm-1.0.2.tar.gz.
File metadata
- Download URL: django_athm-1.0.2.tar.gz
- Upload date:
- Size: 45.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2191ba2282329dbe6221b21cf2d8474ceaba6a3cfd96ba2d271d76c7df8ff510
|
|
| MD5 |
a6f8eefb58308596dbb7af9fef31ad73
|
|
| BLAKE2b-256 |
762c94a1ce34224eaa8a20b50149d8178931c97a998bff0feeff1e0c4751e51e
|
Provenance
The following attestation bundles were made for django_athm-1.0.2.tar.gz:
Publisher:
release.yml on django-athm/django-athm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_athm-1.0.2.tar.gz -
Subject digest:
2191ba2282329dbe6221b21cf2d8474ceaba6a3cfd96ba2d271d76c7df8ff510 - Sigstore transparency entry: 814900467
- Sigstore integration time:
-
Permalink:
django-athm/django-athm@1878f67b00a6bdf602900071c22847ea9010b4e7 -
Branch / Tag:
refs/tags/1.0.2 - Owner: https://github.com/django-athm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1878f67b00a6bdf602900071c22847ea9010b4e7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file django_athm-1.0.2-py3-none-any.whl.
File metadata
- Download URL: django_athm-1.0.2-py3-none-any.whl
- Upload date:
- Size: 56.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc69072dfc4dc15dd5c82d656f92b18d2e4e4708c0d6dc1e3623a7cc76d96033
|
|
| MD5 |
3e836d1125d895d5bb2233ae3042dd21
|
|
| BLAKE2b-256 |
0e93cea5bacd8c551028b9d951afe6a3890b69f3a82809c0ef3df60c05d64d46
|
Provenance
The following attestation bundles were made for django_athm-1.0.2-py3-none-any.whl:
Publisher:
release.yml on django-athm/django-athm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_athm-1.0.2-py3-none-any.whl -
Subject digest:
dc69072dfc4dc15dd5c82d656f92b18d2e4e4708c0d6dc1e3623a7cc76d96033 - Sigstore transparency entry: 814900470
- Sigstore integration time:
-
Permalink:
django-athm/django-athm@1878f67b00a6bdf602900071c22847ea9010b4e7 -
Branch / Tag:
refs/tags/1.0.2 - Owner: https://github.com/django-athm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1878f67b00a6bdf602900071c22847ea9010b4e7 -
Trigger Event:
push
-
Statement type: