Skip to content

SDK-SPEC-PYTHON — Python SDK Specification

Status: Draft Owner: Platform Engineering Package: simpaisa Runtime: Python 3.11+ Last Updated: 2026-04-03


1. Overview

Official Python SDK for the Simpaisa Payment Gateway. Provides synchronous and asynchronous access to Pay-Ins, Pay-Outs, Remittances, and Cards across PK, BD, NP, and IQ corridors. Handles 270M+ annual transactions at $1B+ volume. Published to PyPI as simpaisa.

2. Package Structure

simpaisa/
├── simpaisa/
│   ├── __init__.py            # Public API re-exports
│   ├── client.py              # SimPaisaClient (sync) and AsyncSimPaisaClient
│   ├── config.py              # Configuration dataclass
│   ├── payin/
│   │   ├── __init__.py
│   │   ├── client.py          # PayIn operations (initiate, verify, status, list)
│   │   └── models.py          # Pydantic models for pay-in
│   ├── payout/
│   │   ├── __init__.py
│   │   ├── client.py          # PayOut operations (initiate, status, batch, cancel)
│   │   └── models.py
│   ├── remittance/
│   │   ├── __init__.py
│   │   ├── client.py          # Remittance operations (quote, initiate, status, beneficiaries)
│   │   └── models.py
│   ├── cards/
│   │   ├── __init__.py
│   │   ├── client.py          # Cards operations (pay, capture, void, refund, tokenise)
│   │   └── models.py
│   ├── webhooks/
│   │   ├── __init__.py
│   │   ├── verifier.py        # WebhookVerifier (HMAC-SHA256)
│   │   └── models.py
│   ├── auth/
│   │   ├── __init__.py
│   │   └── rsa_provider.py    # RSAAuthProvider — PEM loading, request signing
│   ├── errors.py              # SimPaisaError hierarchy
│   ├── retry.py               # RetryPolicy with exponential backoff
│   ├── idempotency.py         # IdempotencyKeyGenerator (UUID v7)
│   └── _generated/
│       └── models.py          # Auto-generated from OpenAPI via datamodel-code-generator
├── tests/
├── pyproject.toml
└── py.typed                   # PEP 561 marker

3. Exported Modules

Top-level simpaisa package SHALL export:

  • SimPaisaClient — synchronous client (uses httpx)
  • AsyncSimPaisaClient — async client (uses httpx.AsyncClient)
  • PayIn, PayOut, Remittance, Cards — product modules
  • WebhookVerifier — HMAC-SHA256 signature verification
  • RSAAuthProvider — RSA request signing
  • IdempotencyKeyGenerator — UUID v7 key generation
  • SimPaisaError and subclasses

4. Authentication — RSAAuthProvider

  • Load merchant private key from PEM file path or string
  • Sign request body with RSA-SHA256 using the cryptography library
  • Attach X-Simpaisa-Signature header to each outbound request
  • Attach X-Simpaisa-Merchant-Id header
  • Support key rotation via list of key paths
from simpaisa.auth import RSAAuthProvider

auth = RSAAuthProvider(
    merchant_id="MCH-001",
    private_key_path="./keys/merchant.pem",
)

5. Async Support

  • AsyncSimPaisaClient provides identical API surface using async/await
  • Built on httpx.AsyncClient with connection pooling
  • Context manager support: async with AsyncSimPaisaClient(...) as client:
  • Synchronous client uses httpx.Client (not asyncio wrapper)
async with AsyncSimPaisaClient(config=config) as client:
    result = await client.payin.initiate(request)

6. WebhookVerifier

  • Verify X-Simpaisa-Webhook-Signature using HMAC-SHA256 (hmac stdlib)
  • Constructor accepts webhook secret
  • verify(payload: bytes, signature: str) -> bool
  • Replay protection: validate X-Simpaisa-Webhook-Timestamp within tolerance (default 300s)
  • Raise WebhookVerificationError on failure

7. RetryPolicy

  • Exponential backoff with jitter (base 200ms, max 30s)
  • Configurable max retries (default 3)
  • Retry on: 429, 502, 503, 504, connection errors
  • Never retry: 400, 401, 403, 404, 409, 422
  • Respect Retry-After header
  • on_retry callback for observability

8. Error Handling

SimPaisaError (base)
├── AuthenticationError     — 401/403 responses
├── ValidationError         — 400/422 with field-level details
├── RateLimitError          — 429 with retry_after
├── TimeoutError            — request/connection timeout
├── IdempotencyError        — conflicting idempotency key
├── NetworkError            — connection/DNS failures
└── WebhookVerificationError — signature mismatch

All errors include: code, message, status_code, request_id, retryable.

9. Typed Models (Pydantic)

  • All request and response models SHALL be Pydantic v2 BaseModel subclasses
  • Auto-generated from canonical OpenAPI 3.1 spec via datamodel-code-generator
  • Strict mode enabled: no coercion of incompatible types
  • Custom validators for currency codes, MSISDN formats, corridor-specific rules
  • Models placed in _generated/models.py, re-exported with friendly names

10. Configuration

from simpaisa import SimPaisaClient, Config

client = SimPaisaClient(
    config=Config(
        environment="sandbox",        # "sandbox" | "production"
        merchant_id="MCH-001",
        private_key_path="./keys/merchant.pem",
        timeout=30.0,                 # seconds, default 30
        retries=3,                    # default 3
        logger=custom_logger,         # optional, logging-compatible
    )
)

11. Example Usage

from simpaisa import SimPaisaClient, Config

client = SimPaisaClient(config=Config(
    environment="sandbox",
    merchant_id="MCH-001",
    private_key_path="./keys/merchant.pem",
))

# Pay-In
result = client.payin.initiate(
    amount=5000,
    currency="PKR",
    channel="EASYPAISA",
    customer_msisdn="03001234567",
    callback_url="https://merchant.com/webhook",
)

# Pay-Out
payout = client.payout.initiate(
    amount=10000,
    currency="BDT",
    beneficiary_account="1234567890",
    beneficiary_bank="BRAC",
)

# Webhook verification
from simpaisa.webhooks import WebhookVerifier

verifier = WebhookVerifier(secret="whsec_...")
is_valid = verifier.verify(raw_body, signature_header)

12. Build and Publish

  • Build system: Hatch (PEP 517/518)
  • Test runner: pytest + pytest-asyncio
  • Linting: Ruff (linting + formatting)
  • Type checking: mypy (strict mode)
  • CI: Bitbucket Pipelines — lint → typecheck → test → build → publish
  • Publish: PyPI with trusted publisher (OIDC)
  • Versioning: Semantic versioning; __version__ in __init__.py

13. Compatibility

  • Python 3.11, 3.12, 3.13
  • PEP 561 compliant (py.typed marker)
  • Dependencies: httpx, cryptography, pydantic>=2.0
  • No framework coupling (works with Django, Flask, FastAPI, or standalone)

14. Testing Requirements

  • Unit tests for every public method (>90% coverage)
  • Integration tests against sandbox environment
  • Contract tests validating against OpenAPI spec
  • Async and sync paths both tested
  • Webhook verification round-trip tests
  • Retry behaviour tests with simulated failures (respx for mocking)

15. Documentation

  • Docstrings on all public classes and methods (Google style)
  • Auto-generated reference via Sphinx + autodoc
  • README with quickstart, authentication, and corridor-specific examples
  • CHANGELOG following Keep a Changelog format
  • Type stubs bundled (no separate stubs package)