Skip to main content

Overview

CrediBill is a production-grade billing infrastructure for SaaS applications using African payment providers. It handles subscription billing, payment orchestration, and real-time webhook delivery while maintaining multi-tenant isolation and security.

Key Capabilities

  • Multi-Tenant Architecture: Each SaaS app maintains isolated payment provider credentials
  • 4 African Payment Providers: Flutterwave, PawaPay, Pesapal, DPO
  • Automated Billing Cycles: Cron-based trial expirations, recurring payments, and retries
  • Production-Grade Security: HMAC signature verification, replay attack prevention, encrypted credentials
  • Real-Time Webhooks: Bi-directional webhook delivery with retry logic
  • Comprehensive Logging: Full audit trail of all payment events

Architecture

Multi-Tenant Design

Each SaaS app:
  • Configures their own payment provider credentials
  • Maintains encrypted credential storage
  • Receives isolated webhook events
  • Has payment transactions flow directly to their provider account
CrediBill acts as orchestrator, not custodian - funds never touch CrediBill accounts.

Payment Lifecycle

1. Trial to Paid Conversion

Trigger: Customer’s trial period expires Flow:
Implementation Functions:
  • convex/cronHandlers.ts: processTrialExpirations()
  • convex/payments.ts: initiateSubscriptionPayment()
  • convex/paymentsNode.ts: Provider-specific adapters

2. Recurring Payments

Trigger: Subscription renewal date reached Flow:
Implementation Functions:
  • convex/cronHandlers.ts: processRecurringPayments()
  • convex/payments.ts: processRecurringPayment()

3. Payment Confirmation (Webhook)

Trigger: Payment provider sends webhook confirmation Flow:
Implementation Functions:
  • convex/http.ts: Webhook route handlers
  • convex/webhookActions.ts: Event handlers
  • convex/webhookQueries.ts: Transaction lookups
  • convex/webhookMutations.ts: Status updates
  • convex/outgoingWebhooks.ts: SaaS app notifications

4. Failed Payment Handling

Trigger: Payment fails or webhook indicates failure Flow:
Implementation Functions:
  • convex/cronHandlers.ts: retryFailedPayments()
  • convex/webhookMutations.ts: updateTransactionFromWebhook()

Database Schema

Payment Providers

Payment Transactions

Webhook Logs (Incoming)

Outgoing Webhooks

Security Features

Webhook Signature Verification

All incoming webhooks must be verified using HMAC-SHA256:
Security considerations:
  • Timing-safe comparison: Prevents attackers from determining signature validity through response timing
  • Timestamp validation: Reject webhooks older than 5 minutes (prevent replay attacks)
  • Signature verification: Ensures webhook originated from provider, not attacker

Credential Encryption

All stored provider credentials use AES-256-GCM encryption:
Security implications:
  • Per-app encryption: Each app has isolated encryption keys
  • AES-256-GCM: Authenticated encryption prevents tampering
  • No central key storage: Master key in environment variables

Race Condition Protection

Critical updates use atomic transactions:

Cron Jobs Schedule

Next Steps