Skip to main content
ShadhinPay Docs
Client libraries

Python

Integrate ShadhinPay from Python (Django, FastAPI, Flask, or scripts) today, and track the official SDK.

Official SDK — Planned

A first-party shadhinpay package for PyPI is on the roadmap. Until it ships, requests (or httpx) and the standard library hmac module are all you need.

Create a payment

import os
import uuid
import requests

BASE = "https://api.shadhinpay.pay/api/v1"

def create_payment():
    res = requests.post(
        f"{BASE}/payments",
        headers={
            "Client-Id": os.environ["SHADHINPAY_CLIENT_ID"],
            "Business-Id": os.environ["SHADHINPAY_BUSINESS_ID"],
            "X-Api-Key": os.environ["SHADHINPAY_API_KEY"],
            "X-Idempotency-Key": str(uuid.uuid4()),
        },
        json={
            "amount": "500.00",
            "currency": "BDT",
            "merchantTxnId": "order-7831",
            "callbackUrl": "https://shop.example.com/return",
        },
        timeout=10,
    )
    body = res.json()
    if body.get("status") != "success":
        raise RuntimeError(body.get("errorType"))  # see /docs/developers/errors
    return body["data"]  # {"paymentId": ..., "paymentUrl": ..., ...}

Redirect the customer to data["paymentUrl"]. Parse amount with decimal.Decimal, never float — see Money.

Verify a webhook

Sign over the raw request body before parsing JSON:

import hashlib
import hmac
import time

def verify(raw: bytes, header: str, secret: str) -> bool:
    parts = dict(kv.split("=", 1) for kv in header.split(","))
    try:
        t = int(parts["t"])
    except (KeyError, ValueError):
        return False
    if abs(time.time() - t) > 300:  # replay protection
        return False
    expected = hmac.new(
        secret.encode(), f"t={t}.".encode() + raw, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))

Flask example:

from flask import Flask, request

app = Flask(__name__)

@app.post("/webhooks/shadhinpay")
def webhook():
    raw = request.get_data()  # raw bytes
    sig = request.headers.get("X-ShadhinPay-Signature", "")
    if not verify(raw, sig, os.environ["SHADHINPAY_WEBHOOK_SECRET"]):
        return "", 400
    event = request.get_json()
    # dedupe on event["eventId"], handle event["eventType"]
    return {"status": "received"}, 200

See Webhooks for the full contract.

Next steps

On this page