← Classic portfolio · Studio · Download CV

Backend & Payments Engineer

I build and run the payment and API systems behind a subscription platform.

Three years across .NET, AWS and Python. I own a payments service that supports six gateways across the GCC. I built and maintained the Python API, search, personalization and batch-job platform behind it, and helped move that backend to serverless .NET and containers without breaking live traffic.

~11,000auto-renewals handled in 2025
6payment gateways across the GCC
25payment routes moved from PHP to .NET
10+product and membership launches
4backend languages in production: C#, Python, Go, TypeScript
L2live support for payments, orders and accounts
1,514release and operations requests since 2023
171issues delivered to production in four months

Selected work

Selected projects, each with the problem, what I did and how it was shipped. Company-specific names and internals are left out.

Payments

Auto-renewal engine

Problem. Subscriptions renew on a schedule, so every renewal needs a valid saved payment method and recorded consent.

What I did. Built the renewal log and the auto-renewal consent log (API and database table), VIP-key auto-renewal, and save-card consent for Apple Pay and Google Pay. The scheduled payment routes (wallet and gateway) now run in the .NET service.

Result. About 11,000 renewals handled in 2025 with consent on record for each.

Cron paymentsConsent logAdyenCheckout.com
Product

Membership and product launches

What I did. Supported 10+ product and membership launches since 2023, from new products and VIP keys to the GCC and GCC XL upgrade campaigns (Jun 2026) and Qatar 2027 membership.

Built dynamic upgrade rules so a launch is a configuration change, not a code release.

Dynamic config.NETMySQL
Go

Delivery and call-centre APIs

What I did. Worked on the Go Lambdas behind the delivery and call-centre dashboard: outlet time slots, busy and offline status with automatic return to online, order history and reports, and delivery order status for several delivery partners. Compared old and new Lambdas to prove they matched.

GoStep FunctionsAWS Lambda
Operations

Level-2 live support

What I did. Second line for production: payment and order incidents, customer escalations, data fixes, daily reconciliation, account-deletion requests, and the releases that ship the fixes.

Incident responseCloudWatchSentry
Payments

PHP to .NET payment service

Problem. Payment endpoints ran in legacy PHP and had to move without disrupting live traffic.

What I did. Built the .NET service on ECS Fargate, ported 25 payment routes (Checkout.com and Adyen flows, payment links, refunds, reversals, wallet and scheduled payment jobs) with response-shape parity, and moved traffic route by route behind the load balancer so any route could roll back by changing a rule.

Result. Live payment endpoints now run on a service with health probes, deployment rollback and per-environment Terraform.

.NET 10DapperRedisTerraformECS
API platform

Python to .NET Native AOT Lambdas

Problem. The API ran on Python services that were being replaced by serverless .NET.

What I did. Rewrote 14 APIs (pings, profile, account settings, subscriptions, cheers, ratings, smiles purchase and more) as Native AOT Lambdas, then co-owned the move of the authentication, user, pings and family Lambdas into one monorepo.

Result. A shared library and one pipeline cover 100+ Lambda folders.

AWS LambdaNative AOTJWTxUnit
Product

Request from Friends

Problem. Members had no way to ask a friend to lend an offer the friend held.

What I did. Built six Lambdas (list, send, received, sent, accept, reject), the schema changes and the allowance rules, and shipped them in stages so each piece could be reviewed and released on its own.

C#MySQLAPI Gateway
Platform

Push notification library

Problem. No shared way for Lambdas to notify a user's devices.

What I did. Wrote an FCM HTTP v1 sender that resolves a user's active devices, signs its own service-account assertion to stay compatible with Native AOT, and caches the access token per process.

FCMAOTOAuth
Search & data

Search indices and Glue pipelines

Problem. Search had to stay fresh without downtime.

What I did. Worked on Elasticsearch auto-suggest, filters and geo queries, then on OpenSearch sync jobs: 35-minute delta windows, full rebuilds into a new index, and atomic alias swaps that leave the live index untouched if a load fails. Moved four Glue jobs to Terraform.

OpenSearchGlueTerraform
Security

IAM database authentication

Problem. Lambdas timed out connecting to MySQL.

What I did. Switched to short-lived IAM tokens through RDS Proxy.

Result. No database password lives in function configuration, and the connection path logs separate token signing from network opens, so failures can be diagnosed from CloudWatch.

RDS ProxyIAMSecrets Manager

Python, personalization, jobs and compliance

Before the move to .NET I spent three years in the Python platform. It still runs search, personalization and the scheduled jobs.

API

Flask API and microservices

Extended the main API across versions 65 to 801 (sharing and pings, redemptions, sessions, profile, translations) and worked on separate services for merchant details, delivery and cashless ordering, and user preferences (product subscription and renewal warnings). Run on Gunicorn with Eventlet behind nginx, with Celery for background tasks.

FlaskSQLAlchemyCeleryRedisNew Relic
Personalization

AWS Personalize pipeline

Scheduled jobs export user events from the database and search index to S3, create the dataset group, schemas, datasets, solutions, solution versions, campaigns and filters, import the data and retire old resources. A FastAPI recommendation service with collaborative filtering and event tracking sits beside it.

AWS PersonalizeS3FastAPIscikit-surprise
Batch jobs

Cron and scheduled jobs

Merchant import and update jobs that build search-ready merchant data from many attribute tables, session and ping refresh jobs, index-build and auto-suggest jobs, delivery jobs, and a Glue job for the refer-a-friend flow. Each job logs its status to a table so failed runs can be found and re-run.

PythonAWS GlueMySQLSupervisor
Search

Elasticsearch search APIs

Auto-suggest with a custom analyzer, fuzzy matching, nested offer queries, geo-distance filters and sorting, and per-language indices rebuilt by jobs from a control table.

ElasticsearchOpenSearchGeo queries
Compliance

Privacy, consent and account deletion

Delivered the account-deletion API for members and non-members, consent logging for auto-renewal (API and database table), and consent changes in the user-preferences service. Co-built the legal-documents Lambdas (consent check, account delete and restore) and handle customer deletion requests end to end.

GDPR-style flowsConsent logData retention
Data

SQL and database scripts

Schema and seed scripts for dynamic memberships, shared offers, auto-renewal consent, personalised merchants and delivery types, later moved to versioned migrations.

MySQLAtlas

How the Python platform fits together

Online request path, then the scheduled jobs that feed it.

Client nginxGunicorn + Eventlet Flask routesversions 65 to 801 Auth layerJWT + session keys RepositoriesSQLAlchemy, MySQL Microservicesmerchant, delivery, prefs Celery tasksredemption background work Aurora MySQLreader and writer binds Search + recommendationsElasticsearch, Personalize Redis + monitoringsession keys, New Relic, APM Personalization pipeline EventsMySQL + search index CSV exportto S3 Dataset importschemas, datasets Solution + versionthen campaign, filters Home recommendationsAPI reads the campaign Merchant and search jobs Merchant importattributes to processed data Reindex tablepending indices Delete, createthen bulk import Update jobsincremental changes Search APIssuggest, filters, geo Supervisor-run jobs write their status to tables, so failed runs can be found and repeated. Session and ping refresh jobs call the API and clear Redis keys.

Payments: gateways and how the service stays efficient

I am the owner of this service. It exposes 25 payment routes, and the table shows what each gateway needs from it.

GatewayRoleWhat the service handles
Checkout.comCards, Apple Pay, Google PayPayment sessions, payment detail and statements, webhooks, 3-D Secure redirects, refunds, saved cards
AdyenCards, wallets, payment linksPayment links, Apple Pay and Google Pay configuration, iframe checkout, refunds and reversals
TapRegional cards and walletWallet payments, Apple Pay domain association, order references
TamaraBuy now, pay later (KSA)Webhook integration, stuck-order recovery
TabbyBuy now, pay laterMerchant code and instalment presentation
AtomePay in three instalmentsOrder flow and order-number prefix

Designed for low latency

Async code with cancellation tokens on every call, pooled HTTP clients for outbound gateway calls, Dapper for lean SQL, and response compression.

Designed for fewer database hits

A two-level cache (in-memory in front of Redis) with TTLs matched to how often data changes, from six hours for payment configuration to two weeks for stable mappings.

Designed to fail safely

Short retries where a gateway is eventually consistent, readiness checks on MySQL and Redis, a circuit breaker that rolls back a bad deployment, and two tasks in production.

Designed to cut over safely

Strangler routing: each endpoint moves when its responses match the old ones, and rolls back by changing a load-balancer rule.

Next step I am working on: publishing p50 and p95 latency and error rate per endpoint from production metrics, so the efficiency claims are numbers and not design intent.

Architecture I work in

Simplified. Requests reach serverless Lambdas (.NET and Go), containerised services (payments, TypeScript) or the Python services, and all of them share one data layer.

Apps & web API Gatewayv901 · v902 · v903 Load balancerand nginx .NET & Go Lambdasone per endpoint TypeScript serviceFastify on ECS Payments service.NET on ECS Python servicesFlask, FastAPI, jobs Aurora MySQLRedis · DynamoDB · Secrets Manager Search and recommendationsOpenSearch · Elasticsearch · Personalize Payment gateways · pushCheckout.com · Adyen · FCM

Deployment: one GitHub Actions entry point detects what changed, plans Terraform per environment, deploys production on merge, then cascades to the other environments. Database changes use Atlas migrations and Glue jobs ship through Terraform. The Python services ship through release requests and run under Supervisor.

Stack

Languages

C# / .NETPythonSQLTypeScriptHCLPHP (maintenance)

Cloud

LambdaECS FargateAPI GatewayRDS ProxyGlueS3SQS / EventBridge

Data

MySQL / AuroraRedisDynamoDBOpenSearchElasticsearchAtlas

Delivery

TerraformGitHub ActionsDockerSentryCloudWatch

Experience

Software Engineer, Backend · the ENTERTAINER2023 – presentPython services, personalization and jobs, then serverless .NET, containers, Terraform and payments ownership.
2026Payments and API migrationPayment service on ECS, 25 payment routes migrated, six gateways supported, Request from Friends, push platform.
2025Search and deliveryElasticsearch to OpenSearch support, delivery dashboard APIs, Glue jobs.
2023 – 2024Core API and release ownershipFlask API versions, search, personalization and delivery microservices, cron jobs, consent and account deletion, 1,500+ release and operations requests.

Contact

Email umairrafi672@gmail.com · GitHub MUmairVirk · LinkedIn muhammad-umair-virk