Skip to content
Back to Projects
01/Fintech & SDKCreator & Lead Architect2024 – Present

UnoPay

A strictly-typed, unified TypeScript SDK for managing payments across Iranian Internet Payment Gateways (IPGs). Compatible with Edge, Cloudflare Workers, and Node.js.

Tech StackTYPESCRIPTSDKEDGEPAYMENTSNODE.JSBUNDENO
View Repository
UnoPay
Overview

Problem & solution scope

UnoPay solves the fragmentation and brittle integration challenges of Iranian payment gateways by providing a strongly-typed, single-entrypoint client architecture. Built entirely on standard Web Fetch primitives with zero external runtime dependencies, it runs identically in Vercel Edge, Cloudflare Workers, Node.js 18+, Bun, and Deno.

System Architecture

System architecture

Pluggable Adapter Pattern & Universal Fetch Runtime

The SDK centers on the UnoPay orchestrator client parameterized over configured gateway keys. Each payment provider implements a standardized GatewayAdapter interface exposing uniform createPayment and verifyCallback signatures. Provider-specific payload quirks, error codes, and currency variations are isolated inside adapters, preventing external leakage.

System Components

UnoPay Orchestrator Client

TypeScript Generic Client

Routes requests to configured adapters, enforces strongly-typed gateway keys with autocomplete, and handles centralized lifecycle logging.

Gateway Adapters

Polymorphic Strategy Pattern

Encapsulates SOAP/REST serialization, authentication token negotiation, and response unwrapping for specific gateways.

Currency Normalization Engine

Precision Math & Token Parser

Transparently accepts IRR, IRT, or TOMAN, converting between units with zero loss of precision.

Typed Error Hierarchy

Hierarchical Error Subclasses

Maps arbitrary provider-specific error strings and network timeouts to typed exceptions (PaymentValidationError, GatewayProviderError, GatewayNetworkError).

Data & Execution Flow

01
Client Initialization

Consumer configures UnoPay with strongly-typed gateway adapters (e.g. ZarinpalAdapter) and optional structured loggers.

02
Payment Request

Client calls createPayment(provider, request). Amount is normalized to the target gateway currency and validated.

03
Gateway Handshake

Adapter executes fetch request, negotiates transaction authority/token, and returns a unified redirect URL.

04
Callback Verification

Webhook payload from framework request is parsed, verified against gateway authority, and settled.

Key Capabilities

Engineered capabilities

[01]

Universal Runtime: 100% standard Fetch API compatible with Cloudflare Workers, Vercel Edge, Bun, Deno, and Node.js.

[02]

Strict Zero-Any Typing: Gateway identifiers and response schemas are strictly inferred and autocompleted.

[03]

Automatic Currency Normalization: Seamlessly handles IRR, IRT, and TOMAN conversions.

[04]

Framework-Agnostic Webhooks: Verifies callbacks directly from Express, Fastify, Next.js, Hono, or native Request.

[05]

Standardized Error Classification: Predictable exception hierarchy across all third-party providers.

Technical Decisions & Trade-offs

Engineering trade-offs

Zero-Dependency Footprint

Avoided heavy HTTP libraries; standardizing on the native global fetch API ensures compatibility with edge runtimes and keeps bundle size minimal.

Generic Key Inference

Configured adapters define the valid string literal types for payment dispatch, providing compile-time errors if an unconfigured gateway is invoked.

Implementation & Usage

Unified Payment Initiation & Verification

// typescriptsnippet
import { UnoPay, ZarinpalAdapter } from 'unopay';

const unopay = new UnoPay({
  zarinpal: new ZarinpalAdapter({
    merchantId: process.env.ZARINPAL_MERCHANT_ID!,
    sandbox: process.env.NODE_ENV !== 'production',
  }),
});

// Create payment across any configured provider
const payment = await unopay.createPayment('zarinpal', {
  amount: 50000,
  currency: 'IRT',
  callbackUrl: 'https://mysite.com/api/payment/callback',
  metadata: { description: 'Order #1024' },
});

// Redirect user: payment.redirectUrl
Back to ProjectsView Repository