Backend Engineering, Integration
E-Commerce SaaS
2022-2024
Three payment gateways. Three architectures. One reliable checkout.
A SaaS platform selling digital download codes needed to accept credit cards, PayPal, and European bank transfers. Each gateway had a fundamentally different integration pattern: Braintree processed cards synchronously in a single API call, PayPal required a redirect-and-return flow with a separate execution step, and Sofort operated entirely through asynchronous XML webhooks. The original implementation treated each as a standalone code path, with duplicated finalization logic and no protection against price manipulation between approval and execution.
Three Gateways, Three Failure Modes
Each payment provider imposed a different contract. Braintree returned a result object immediately - success or failure in one round-trip. PayPal required the user to leave the site, approve on paypal.com, then return, at which point the system had to make a second API call to execute the charge. Sofort was the most complex: the system posted XML to create a transaction, redirected the user to their bank's website, then waited for webhook notifications that arrived minutes to hours later. A single order could end up in a limbo state if the PayPal redirect timed out, if Sofort's webhook never arrived, or if the user modified their code package between initiating and completing payment. The finalization logic - generating codes, sending invoices, calculating referral commissions - was copy-pasted across all three paths, each with slightly different error handling.
PayPal redirects you offsite. Sofort sends a webhook hours later. Both need to finalize the same order. The code was duplicated three times.
Unified Finalization with Per-Gateway Adapters
I restructured the payment layer around a clear separation: gateway-specific logic handles the mechanics of each provider, but every successful charge converges into a shared finalization path. Credit card payments call Braintree's API and finalize inline. PayPal payments re-validate the price on return before executing, catching any tampering during the redirect window. Sofort payments lock the code package as non-editable when initiated and rely on webhook notifications to trigger finalization. The referral commission calculation, code generation, and invoice dispatch run identically regardless of which gateway completed the charge.
The credit card flow - synchronous, single round-trip:
@standard_ajax
def create_braintree_payment(request, code_package):
nonce = request.POST.get('payment_method_nonce')
amount = str(code_package.calculated_price)
result = braintree.Transaction.sale({
'amount': amount,
'payment_method_nonce': nonce,
'merchant_account_id': get_merchant_account(
code_package.currency
),
'options': {'submit_for_settlement': True},
})
if result.is_success:
code_package.paid = True
code_package.payment_method = 'braintree'
code_package.transaction_id = result.transaction.id
code_package.save()
generate_codes(code_package)
send_invoice_email(code_package)
create_referral_commission(code_package)
return AJAX_RESULT_SUCCESS, 'Payment processed.'
return AJAX_RESULT_FAILED, result.messageHow Each Payment Flow Operates
Select a gateway to watch its flow animate. Toggle 'Price changed during approval' to see PayPal's re-validation catch a mismatch.
PayPal return handler with price re-validation:
def execute_paypal_payment(request):
payment_id = request.GET.get('paymentId')
payer_id = request.GET.get('PayerID')
package_id = request.GET.get('package_id')
code_package = CodePackage.objects.get(pk=package_id)
payment = paypalrestsdk.Payment.find(payment_id)
# Re-validate: price may have changed during redirect
current_price = code_package.calculated_price
stored_price = Decimal(
payment.transactions[0].amount.total
)
if current_price != stored_price:
send_admin_alert(
f'Price mismatch: {current_price} vs {stored_price}'
)
payment.void()
return redirect_with_error(
'payment-cancelled'
)
if payment.execute({'payer_id': payer_id}):
code_package.paid = True
code_package.payment_method = 'paypal'
code_package.transaction_id = payment_id
code_package.save()
generate_codes(code_package)
send_invoice_email(code_package)
create_referral_commission(code_package)
return redirect('payment-success')
return redirect_with_error('payment-failed')Edge Cases in Production
Sofort Timeout Recovery
When a Sofort payment is initiated, the code package becomes non-editable. If the user abandons the bank's page or the webhook never arrives, a valid_time timestamp controls when editability is restored. On every subsequent access, the system checks datetime.now() > payment.valid_time and re-enables editing once the timeout passes. No cron job needed.
Decimal Precision for Referrals
Referral commissions are calculated as Decimal(float(amount) * REFERRAL_SHARE), then rounded to cents via int(referral_share * 100) / 100.0. This avoids floating-point drift that could create one-cent discrepancies between the commission record and the actual payout. The same formula runs identically across all three gateway paths.
Idempotent Code Generation
Sofort sends both a 'pending' and a 'received' notification for a single successful payment. The generate_codes() function is idempotent - calling it twice produces the same output. The 'received' webhook safely re-runs generation and marks the package as paid, even if 'pending' already did both. No duplicate codes, no double charges.
Sofort webhook handler with state machine transitions:
@csrf_exempt
def sofort_notification(request):
xml = xmltodict.parse(request.body)
txn_id = xml['status_notification']['transaction']
status = xml['status_notification']['status']
payment = SofortPayment.objects.get(
transaction_id=txn_id
)
code_package = payment.code_package
if status == 'pending':
code_package.paid = True
code_package.payment_method = 'sofort'
code_package.save()
generate_codes(code_package)
send_invoice_email(code_package)
create_referral_commission(code_package)
elif status == 'received':
# Idempotent: safe to re-run
generate_codes(code_package)
code_package.paid = True
code_package.save()
elif status == 'loss':
code_package.editable = False
code_package.lock_reason = 'Payment failed'
code_package.save()
elif status == 'refunded':
code_package.editable = False
code_package.lock_reason = 'Payment refunded'
code_package.save()
return HttpResponse(status=200)Reliable Multi-Gateway Checkout at Scale
The restructured payment layer handled three gateway architectures through a unified pipeline. PayPal price manipulation attempts were caught and logged before execution. Sofort's asynchronous webhooks finalized orders within seconds of bank confirmation. The duplicated finalization code was consolidated, eliminating the drift between gateway paths that had caused intermittent referral calculation errors. The checkout operated continuously across all three rails without a single lost transaction.
KEY METRICS
"We went from debugging payment edge cases every week to a system that just works. The PayPal price validation alone stopped two attempted exploits in the first month."
CTO
E-Commerce SaaS · Digital Products