All projects

Mobile money aggregator for Africa: one API in front of Orange Money, Wave, MTN, Airtel and M-Pesa.

Client
Cauris Pay
Key result
One integration for every mobile money operator

Context

Merchants had to integrate each operator separately, each with its own API, callback format and failure modes. Retries and late callbacks made double charges a real risk.

What I built

A single payment API with one adapter per operator behind a common contract, normalized statuses and webhooks, and idempotency keys enforced end to end so a retried request can never charge a customer twice. Around the core: a hosted checkout, a merchant dashboard and an admin console in Angular, developer documentation, a Next.js marketing site, and CaurisFlux, a Europe to Africa money transfer app in React Native.

Result

Merchants go live on every operator through one documented integration instead of five.

Architecture

  1. One adapter per aggregator

    Operators sit behind a common interface, so adding one does not touch the payment engine, and a circuit breaker keeps a failing provider from slowing down the others.

  2. Idempotency on every money-moving endpoint

    A double click or a network retry replays the first response instead of charging the customer twice.

  3. Callbacks verified before they count

    Operator callbacks go through an IP allowlist and a timestamped HMAC signature, and a Redis nonce rejects replays, so a forged callback cannot mark a payment as paid.

  4. A ledger, not just a balance

    Each credit is written in a SQL transaction with a row lock and a before and after movement, so balances always match their history, even under concurrent payments.

  5. Signed, retried webhooks

    Merchants verify each notification with an HMAC signature, and failed deliveries are retried from a queue.

  6. Reconciliation of pending payments

    A job asks the operators about pending transactions every five minutes, so a lost callback never leaves a payment stuck.

  7. A quality gate before every release

    GitLab CI runs lint, type checks, SonarQube, the build and the tests before it builds the Docker image and triggers the deployment.

Stack

  • NestJS
  • Angular
  • Nx
  • PostgreSQL
  • Redis
  • Bull
  • Next.js
  • React Native
  • Docker
  • GitLab CI
  • SonarQube