PayU India Python Integration

raw JSON →
payu_websdk (GitHub only) verified Tue May 12 auth: no python install: stale quickstart: stale

PayU India payment gateway. PACKAGE NAME CONFUSION: 'payu' on PyPI (1.2.1) is an unrelated HPC workflow tool — NOT PayU payments. Official PayU India Python SDK is 'payu_websdk' (from payu-india/web-sdk-python on GitHub, not on PyPI). 'payu-sdk' (1.2.0 on PyPI) is unofficial/community. Most Python integrations use manual hash generation without any SDK. Core requirement: SHA512 hash must be generated server-side for every transaction. Amount as string in rupees. Test environment: test.payu.in, Live: secure.payu.in.

pip install git+https://github.com/payu-india/web-sdk-python.git
breaking 'payu' on PyPI is an HPC workflow scheduling tool — completely unrelated to PayU India payments. 'pip install payu' installs the wrong thing.
fix Use payu_websdk (install from GitHub) or implement hash generation manually with requests.
breaking Hash formula requires exactly 6 pipe characters between udf5 and salt: key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt. Wrong pipe count causes PayU to reject the transaction with 'hash mismatch' error.
fix Count pipes: after udf5 there are 6 consecutive pipes before salt. Use f-string: f'...{udf5}||||||{salt}'
breaking Amount must be a string with 2 decimal places — not an integer or float. '500.00' not 500 or 500.0. Wrong type causes hash mismatch.
fix amount = f'{float_amount:.2f}' — always format to 2 decimal places as string.
breaking Hash must be lowercase. SHA512 output must be converted with .lower(). Uppercase hash causes payment failure.
fix hashlib.sha512(hash_str.encode()).hexdigest().lower()
gotcha Reverse hash verification mandatory after payment. PayU returns hash in reverse order: sha512(SALT|status||||||udf5|udf4|udf3|udf2|udf1|email|firstname|productinfo|amount|txnid|key). Must verify this on your server.
fix Implement reverse hash: salt|status||||||udf5|udf4|...|key and compare with hash returned in PayU callback.
gotcha Test environment: test.payu.in. Production: secure.payu.in. Using production URL with test keys or vice versa causes connection failure.
fix TEST: POST to https://test.payu.in/_payment. LIVE: POST to https://secure.payu.in/_payment.
gotcha txnid must be unique for every transaction — max 25 chars, alphanumeric. Duplicate txnid causes 'duplicate transaction' error.
fix Use UUID: import uuid; txnid = str(uuid.uuid4()).replace('-', '')[:25]
breaking Installing Python packages directly from GitHub (e.g., 'pip install git+...' as suggested for 'payu_websdk') requires the 'git' command-line tool to be installed on your system. The error 'No such file or directory: git' indicates that git is missing or not in your system's PATH.
fix Ensure 'git' is installed in your environment. For 'python:3.9-slim' or similar Debian-based images, add `apt-get update && apt-get install -y git` to your Dockerfile. For other environments, install 'git' via your system's package manager or from git-scm.com and ensure it's in your PATH.
breaking The error "Cannot find command 'git'" indicates that 'git' is not installed or not in the system's PATH. This is a common requirement for `pip install` when a dependency is fetched directly from a Git repository (e.g., using `git+https://`).
fix Ensure 'git' is installed on the system and available in the PATH. For Alpine-based images, you typically install it using `apk add git`.
python os / libc status wheel install import disk
3.10 alpine (musl) - - - -
3.10 slim (glibc) - - - -
3.11 alpine (musl) - - - -
3.11 slim (glibc) - - - -
3.12 alpine (musl) - - - -
3.12 slim (glibc) - - - -
3.13 alpine (musl) - - - -
3.13 slim (glibc) - - - -
3.9 alpine (musl) - - - -
3.9 slim (glibc) - - - -

PayU India — manual hash generation and payment form data preparation.

import hashlib
import requests
import uuid

# PayU credentials from dashboard.payu.in
KEY = 'your_merchant_key'
SALT = 'your_merchant_salt'
ENV = 'test'  # 'test' or 'prod'

BASE_URL = 'https://test.payu.in' if ENV == 'test' else 'https://secure.payu.in'

def generate_hash(key, txnid, amount, productinfo, firstname, email, salt, **udf):
    udf1 = udf.get('udf1', '')
    udf2 = udf.get('udf2', '')
    udf3 = udf.get('udf3', '')
    udf4 = udf.get('udf4', '')
    udf5 = udf.get('udf5', '')
    hash_str = f'{key}|{txnid}|{amount}|{productinfo}|{firstname}|{email}|{udf1}|{udf2}|{udf3}|{udf4}|{udf5}||||||{salt}'
    return hashlib.sha512(hash_str.encode()).hexdigest().lower()

# Create payment params
txnid = str(uuid.uuid4())[:20]
amount = '500.00'  # string, rupees

hash_val = generate_hash(
    KEY, txnid, amount,
    'Widget', 'John', 'john@example.com',
    SALT
)

payment_data = {
    'key': KEY,
    'txnid': txnid,
    'amount': amount,
    'productinfo': 'Widget',
    'firstname': 'John',
    'email': 'john@example.com',
    'phone': '9999999999',
    'surl': 'https://yourapp.com/payment/success',  # success URL
    'furl': 'https://yourapp.com/payment/failure',  # failure URL
    'hash': hash_val,
}
# POST this form data to BASE_URL/_payment
print('POST to:', f'{BASE_URL}/_payment')
print('Params:', payment_data)