---
title: "Building a Zero-Fee Payment API: Technical Decisions"
description: "The architecture and technical decisions behind HMD Payments - a zero-fee payment platform supporting crypto, Papara, IBAN, and card transactions."
date: 2025-01-05T00:00:00.000Z
category: Architecture
readingTime: "3 min read"
---


When we set out to build HMD Payments, the premise sounded simple: a payment API with zero fees. The technical reality was anything but simple. This is a post about the architectural decisions - the ones we got right, and the ones that cost us weeks.

## The Problem We Were Solving

Most payment APIs in our market charged between 2-5% per transaction. For small businesses and creators, these fees ate into margins. We wanted to build something that eliminated the middleman fee through direct integrations with payment providers: Papara, bank IBAN transfers, cryptocurrency, and card processors.

The business model was sustainable through volume-based institutional agreements rather than per-transaction fees to the merchant.

## API Design: REST, Not GraphQL

We chose REST. In fintech, predictability matters more than flexibility. Every payment operation maps cleanly to a resource and an HTTP method:

- `POST /v1/payments` - Create a payment intent
- `GET /v1/payments/:id` - Retrieve payment status
- `POST /v1/refunds` - Initiate a refund
- `GET /v1/transactions` - List transactions with pagination

GraphQL would have introduced unnecessary complexity for an API where the query patterns are well-known and fixed. Payment integrations don't benefit from ad-hoc queries - they benefit from predictable, well-documented endpoints.

## Idempotency: The Non-Negotiable

In payments, the worst thing that can happen isn't a failed transaction - it's a duplicate transaction. A network timeout, a retried request, a client bug - any of these could cause a double charge. Idempotency keys prevent this.

Every mutating request requires an `Idempotency-Key` header. The server stores the key and its response. If the same key is sent again, the server returns the cached response without re-executing the operation.

This isn't optional in payment systems. It's the difference between "we can recover" and "we just charged someone twice."

## Multi-Provider Architecture

The core architectural challenge was supporting multiple payment providers behind a single API surface. A merchant shouldn't need to know whether a payment is being processed via Papara, IBAN, or card - they make one API call and we route it.

We used a provider abstraction:

```
PaymentIntent
├── ProviderRouter (selects provider based on method + currency)
├── PaparaProvider
├── IBANProvider  
├── CryptoProvider
└── CardProvider
```

Each provider implements a common interface: `createPayment()`, `checkStatus()`, `refund()`. The router selects the provider based on the payment method the merchant specifies. This made adding new providers straightforward - implement the interface, register the provider, done.

## Webhook Reliability

Payment events need to reach merchants reliably. A missed webhook means a merchant doesn't know they've been paid. We built the webhook system with guaranteed delivery:

1. **Queue all events.** Every payment state change is written to a persistent queue.
2. **Retry with backoff.** Failed deliveries are retried with exponential backoff - 1 min, 5 min, 30 min, 2 hours, 24 hours.
3. **Dead letter queue.** After 5 failed attempts, the event moves to a dead letter queue for manual review.
4. **Signature verification.** Every webhook includes an HMAC signature so merchants can verify authenticity.

## Security Architecture

Handling money means handling trust. Our security posture included:

- **API key scoping.** Each key has explicit permissions - a key that can create payments can't necessarily issue refunds.
- **Request signing.** Critical operations require request body signing, not just authentication.
- **Rate limiting.** Per-key rate limits prevent abuse. Configurable per merchant based on their plan.
- **Audit logging.** Every API call is logged with full request/response metadata. Immutable, append-only, retained for 7 years.

## What Led to the Acquisition

HMD Payments was acquired in 2022. The technical due diligence focused heavily on three things:

1. **API design quality.** Clean, well-documented, versioned. The acquiring company could integrate it without extensive refactoring.
2. **Multi-provider flexibility.** Adding new payment methods required implementing one interface, not rewriting infrastructure.
3. **Reliability track record.** Over 2 million transactions processed with zero data loss incidents.

## Lessons Learned

- **Start with compliance.** Don't bolt on regulatory compliance later. Design with it from day one.
- **Idempotency isn't optional.** In any system that handles money or irreversible operations, idempotency keys are mandatory.
- **Boring technology for the foundation.** We used PostgreSQL for transactions (ACID matters when money is involved) and Redis for caching. No exotic tech in the critical path.

Building a payment system teaches you that reliability isn't a feature - it's the product. Everything else is a nice-to-have.

---

*If you're building a fintech product, start with idempotency and audit logging. Everything else can be iterated on. Those two can't.*
