Payments portal · Tech Lead · Oct 2023 — Present · 1 min read
A 12-step payment workflow for high-value luxury itineraries, with automatic refunds on failure.

- Step payment workflow
- 12
- Brands
- 3
- Currency
- Multi
The problem
Staff needed to take and refund payments on high-value itineraries across three brands, and every payment had to land correctly in both the card processor and the reservation system.
What we did
- Built a payments dashboard with reservation-level tracking, status (Active, Overdue), user and date filters, and brand-level visibility.
- Created payment links from SoftTrip reservation details, and manual charges with due dates, reasons and credit card fee waivers with reason tracking.
- Built refund flows that pull transaction history by SoftTrip reservation ID for partial or full refunds.
- Orchestrated each payment through a 12-step AWS Step Functions state machine: validation, CyberSource tokenisation and charge, SoftTrip financial recording, confirmation email, and automated refund on failure.
Key decisions
- 01
Step Functions to orchestrate each payment
Trade-off: More infrastructure than a single API call, in exchange for visible, retryable steps for every payment.
- 02
Automatic refund when a later step fails
Trade-off: More states to design and test, so a guest is never charged for a payment that was not recorded.
- 03
Retries with exponential backoff and dead-letter queues
Trade-off: Failures resolve later instead of instantly, but none are silently dropped.
Architecture
Hover or tab through the components to trace the data path.
- Payments portal — Dashboard, payment links, charges, refunds
- NestJS + tRPC — Validates requests, starts workflows
- PostgreSQL — Payment and transaction records (Prisma)
- Step Functions — 12-step payment state machine
- CyberSource — Tokenisation and charge
- SoftTrip — Reservations and financial recording
- Email — Confirmation emails
- SQS DLQ — Retries with backoff, dead-letter queue
Screenshots
Manual charge with fee waiver
Refund from transaction history
Result
Every payment runs through the same 12-step workflow, and a failure anywhere triggers an automatic refund instead of a manual clean-up.
What I learned
- 01
For money movement, make every step observable before making it fast.
- 02
Design the failure path first; the happy path is the easy part.
Stack
- AWS Step Functions
- Lambda
- CyberSource
- NestJS
- tRPC
- Prisma
- PostgreSQL
- AWS SQS
- TypeScript
Want something like this for your business?