Skip to main content

Unified Python SDK for Pakistani payment gateways (EasyPaisa, JazzCash, HBL, ABL, UBL, etc.)

Project description

raqm-core

Unified Python SDK for Pakistani payment gateways.

One async, type-safe interface across multiple processors — EasyPaisa, JazzCash, HBL, ABL, UBL, and more.

⚠️ Work in progress. Currently only EasyPaisa is fully implemented. Contributions welcome!


Supported Gateways

Gateway Status
EasyPaisa ✅ Live
JazzCash 🚧 Header utils ready
HBL 📅 Planned
ABL 📅 Planned
UBL 📅 Planned
📅 Your gateway here

Features

  • Async-first — built on httpx.AsyncClient for non-blocking I/O
  • Type-safe — all responses are validated through Pydantic models
  • Consistent API — same patterns across all gateways
  • Mock-friendly — inject your own httpx.AsyncClient for testing
  • Minimal dependencies — just httpx and pydantic

Installation

pip install raqm-core

Or with uv:

uv add raqm-core

Requires Python 3.12+.


Quick Start

import asyncio
from raqm_core import EasyPaisa


async def main():
    ep = EasyPaisa(
        store_id="43",
        username="your_username",
        password="your_password",
        sandbox=True,
    )

    result = await ep.pay_via_ma(
        order_id="order_123",
        amount="1000.00",
        email="customer@example.com",
        mobile_number="03451234567",
    )

    print(f"Status: {result.responseCode}{result.responseDesc}")
    print(f"Transaction ID: {result.transactionId}")


asyncio.run(main())

Usage

EasyPaisa

Initialisation

from raqm_core import EasyPaisa

ep = EasyPaisa(
    store_id="43",
    username="your_username",
    password="your_password",
    sandbox=True,           # set False for production
)

You can optionally inject your own httpx.AsyncClient — useful for testing with httpx.MockTransport:

import httpx

client = httpx.AsyncClient(...)
ep = EasyPaisa(store_id="43", username="...", password="...", sandbox=True, client=client)

Mobile Account (MA) Payment

result = await ep.pay_via_ma(
    order_id="order_123",
    amount="500.00",
    email="customer@example.com",
    mobile_number="03451234567",
)

# EasyPaisaMAResponse fields:
result.orderId           # str
result.storeId           # int
result.transactionId     # str
result.transactionDateTime  # str (dd/MM/yyyy hh:mm AM/PM)
result.responseCode      # EasypaisaResponseCode (enum)
result.responseDesc      # str

Over-the-Counter (OTC) Payment

result = await ep.pay_via_otc(
    order_id="order_456",
    amount="1500.00",
    email="customer@example.com",
    msisdn="03451234567",
    token_expiry="01/01/2025 11:59 PM",
)

# EasyPaisaOTCResponse fields (extends base):
result.paymentToken              # str
result.paymentTokenExpiryDateTime  # str

Transaction Inquiry

result = await ep.inquire_transaction_status(
    order_id="order_123",
    account_number="123456789",
)

# EasyPaisaInquireTransactionResponse fields:
result.transactionStatus   # str (e.g. "COMPLETED")
result.transactionAmount   # str
result.accountNum          # str
result.storeName           # str
result.msisdn              # str
result.paymentMode         # str ("MA", "OTC", "CC")

Architecture

Each payment gateway follows a consistent 3-layer structure:

src/
├── <gateway>.py              # Client class — public API
├── headers/
│   └── <gateway>.py          # Auth / signing helpers
└── schemas/
    └── <gateway>.py          # Pydantic request/response models

Current structure:

src/
├── easypaisa.py              # EasyPaisa client
├── headers/
│   ├── easypaisa.py          # Basic Auth header
│   └── jazzcash.py           # SHA-256 secure hash
└── schemas/
    └── easypaisa.py          # EasyPaisa Pydantic models

tests/
├── test_easypaisa.py         # EasyPaisa integration tests
└── headers/
    ├── test_easypaisa.py     # Auth header unit tests
    └── test_jazzcash.py      # Secure hash unit tests

Adding a New Gateway

Want to add support for a new processor? Follow this checklist.

1. Research the API

Understand the gateway's:

  • Authentication mechanism (Basic Auth, HMAC, API key, etc.)
  • Endpoints and request/response formats
  • Error/response codes

2. Create header helpers

src/headers/<gateway>.py — authentication or signing logic.

# src/headers/hbl.py
def generate_signature(api_key: str, payload: dict) -> str:
    ...

Write unit tests in tests/headers/test_<gateway>.py.

3. Create Pydantic schemas

src/schemas/<gateway>.py — response models and enums.

# src/schemas/hbl.py
from pydantic import BaseModel, Field


class HBLResponse(BaseModel):
    orderId: str = Field(...)
    responseCode: str = Field(...)
    responseDesc: str = Field(...)

4. Create the client class

src/<gateway>.py — async client with a _post() helper and public methods.

# src/hbl.py
import httpx
from .headers.hbl import generate_signature
from .schemas.hbl import HBLResponse


class HBL:
    def __init__(self, api_key: str, sandbox: bool, client: httpx.AsyncClient | None = None):
        self._client = client or httpx.AsyncClient()
        ...

    async def _post(self, endpoint: str, payload: dict) -> dict:
        ...

    async def pay(self, order_id: str, amount: str, ...) -> HBLResponse:
        ...

5. Write integration tests

tests/test_<gateway>.py — use httpx.MockTransport to mock responses.

# tests/test_hbl.py
import httpx
import pytest
from raqm_core import HBL


@pytest.mark.asyncio
async def test_pay_success():
    def handler(request: httpx.Request) -> httpx.Response:
        return httpx.Response(status_code=200, json={...})

    client = httpx.AsyncClient(transport=httpx.MockTransport(handler))
    hbl = HBL(api_key="test", sandbox=True, client=client)
    result = await hbl.pay(...)
    assert result.responseCode == "0000"

6. Update this README

Add the new gateway to the Supported Gateways table with the appropriate status badge.


Roadmap

  • EasyPaisa (MA, OTC, inquiry)
  • JazzCash client + schemas
  • HBL payment gateway
  • ABL payment gateway
  • UBL payment gateway
  • Standardised error handling across gateways
  • Request/response logging middleware
  • CI/CD + automated testing

Development

# Clone the repo
git clone https://github.com/your-username/raqm-core.git
cd raqm-core

# Create a virtual environment
uv venv
source .venv/bin/activate

# Install dependencies
uv sync

# Run tests
pytest

Contributing

Contributions are welcome! See Adding a New Gateway for the detailed guide.

Please open an issue first to discuss your proposed changes.


License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

raqm_core-0.1.0.tar.gz (8.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

raqm_core-0.1.0-py3-none-any.whl (6.7 kB view details)

Uploaded Python 3

File details

Details for the file raqm_core-0.1.0.tar.gz.

File metadata

  • Download URL: raqm_core-0.1.0.tar.gz
  • Upload date:
  • Size: 8.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"43","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for raqm_core-0.1.0.tar.gz
Algorithm Hash digest
SHA256 06fc2b3bd80cf9c571171f88e9a79ed3aa7b847fbdf07f8266ecc92d734228b1
MD5 0e2c202b985a81bd32a6821d259225f0
BLAKE2b-256 c1e7ce39b42a881eacd7e8ea97365f698557ea60ea98bebd5542d26b9c28b9b0

See more details on using hashes here.

File details

Details for the file raqm_core-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: raqm_core-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 6.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"43","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for raqm_core-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9f1a688cdbb91b79447a5f3056a4c90869db1827ac156ce949355c8325f58dad
MD5 8b39730cce0072338e6679952608e6ac
BLAKE2b-256 4b10957b635fcb10b149093e1883e3866b3d7ac8dfd9cb7e0d55b4b82a77c25f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page