{"id":183,"library":"payu","title":"PayU India Python Integration","description":"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.","status":"active","version":"payu_websdk (GitHub only)","language":"python","source_language":"en","source_url":"https://github.com/payu-india/web-sdk-python","tags":["payu","payments","india","fintech","python","payment-gateway","sha512"],"install":[{"cmd":"pip install git+https://github.com/payu-india/web-sdk-python.git","lang":"bash","label":"Python (official PayU web SDK — GitHub only, not on PyPI)"}],"dependencies":[{"reason":"Required for manual API integration and for payu_websdk.","package":"requests","optional":false}],"imports":[{"note":"Hash must include udf1-udf5 fields (even if empty) followed by exactly 6 pipe characters before salt. Wrong pipe count causes hash mismatch and payment failure.","wrong":"# Wrong: amount as int\ngenerate_payu_hash(..., amount=500, ...)  # must be string\n\n# Wrong: uppercase hash\nreturn hashlib.sha512(...).hexdigest().upper()  # must be lowercase\n\n# Wrong: wrong pipe count between udf5 and salt\nhash_str = f'{key}|{txnid}|{amount}|{productinfo}|{firstname}|{email}|{salt}'  # missing udf fields","symbol":"Hash generation (manual — recommended approach)","correct":"import hashlib\n\ndef generate_payu_hash(key, txnid, amount, productinfo,\n                      firstname, email, salt,\n                      udf1='', udf2='', udf3='', udf4='', udf5=''):\n    \"\"\"\n    PayU hash formula:\n    sha512(key|txnid|amount|productinfo|firstname|email|\n           udf1|udf2|udf3|udf4|udf5||||||salt)\n    Amount must be a string. Hash must be lowercase.\n    \"\"\"\n    hash_str = (\n        f'{key}|{txnid}|{amount}|{productinfo}|{firstname}|{email}|'\n        f'{udf1}|{udf2}|{udf3}|{udf4}|{udf5}||||||{salt}'\n    )\n    return hashlib.sha512(hash_str.encode('utf-8')).hexdigest().lower()\n\n# Usage\nhash_val = generate_payu_hash(\n    key='your_key',\n    txnid='unique_txn_001',\n    amount='500.00',   # string, in rupees\n    productinfo='Widget',\n    firstname='John',\n    email='john@example.com',\n    salt='your_salt'\n)\nprint(hash_val)"},{"note":"'import payu' imports an HPC scheduling tool, not PayU payments. payu_websdk is the correct import for PayU India SDK.","wrong":"# Wrong: 'payu' package from PyPI is a HPC workflow tool\nimport payu\nclient = payu.something()  # completely unrelated package","symbol":"payu_websdk Client","correct":"import payu_websdk\n\n# ENV: 'TEST' or 'LIVE'\nclient = payu_websdk.Client('YOUR_KEY', 'YOUR_SALT', 'TEST')\n\n# Verify payment status\nresult = client.verify_payment('txnid_001')\nprint(result)\n\n# Refund\nrefund = client.refund_transaction(\n    mihpayid='payu_transaction_id',\n    token='unique_refund_token',\n    amount='100.00'\n)\nprint(refund)"}],"quickstart":{"code":"import hashlib\nimport requests\nimport uuid\n\n# PayU credentials from dashboard.payu.in\nKEY = 'your_merchant_key'\nSALT = 'your_merchant_salt'\nENV = 'test'  # 'test' or 'prod'\n\nBASE_URL = 'https://test.payu.in' if ENV == 'test' else 'https://secure.payu.in'\n\ndef generate_hash(key, txnid, amount, productinfo, firstname, email, salt, **udf):\n    udf1 = udf.get('udf1', '')\n    udf2 = udf.get('udf2', '')\n    udf3 = udf.get('udf3', '')\n    udf4 = udf.get('udf4', '')\n    udf5 = udf.get('udf5', '')\n    hash_str = f'{key}|{txnid}|{amount}|{productinfo}|{firstname}|{email}|{udf1}|{udf2}|{udf3}|{udf4}|{udf5}||||||{salt}'\n    return hashlib.sha512(hash_str.encode()).hexdigest().lower()\n\n# Create payment params\ntxnid = str(uuid.uuid4())[:20]\namount = '500.00'  # string, rupees\n\nhash_val = generate_hash(\n    KEY, txnid, amount,\n    'Widget', 'John', 'john@example.com',\n    SALT\n)\n\npayment_data = {\n    'key': KEY,\n    'txnid': txnid,\n    'amount': amount,\n    'productinfo': 'Widget',\n    'firstname': 'John',\n    'email': 'john@example.com',\n    'phone': '9999999999',\n    'surl': 'https://yourapp.com/payment/success',  # success URL\n    'furl': 'https://yourapp.com/payment/failure',  # failure URL\n    'hash': hash_val,\n}\n# POST this form data to BASE_URL/_payment\nprint('POST to:', f'{BASE_URL}/_payment')\nprint('Params:', payment_data)","lang":"python","description":"PayU India — manual hash generation and payment form data preparation."},"warnings":[{"fix":"Use payu_websdk (install from GitHub) or implement hash generation manually with requests.","message":"'payu' on PyPI is an HPC workflow scheduling tool — completely unrelated to PayU India payments. 'pip install payu' installs the wrong thing.","severity":"breaking","affected_versions":"all"},{"fix":"Count pipes: after udf5 there are 6 consecutive pipes before salt. Use f-string: f'...{udf5}||||||{salt}'","message":"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.","severity":"breaking","affected_versions":"all"},{"fix":"amount = f'{float_amount:.2f}' — always format to 2 decimal places as string.","message":"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.","severity":"breaking","affected_versions":"all"},{"fix":"hashlib.sha512(hash_str.encode()).hexdigest().lower()","message":"Hash must be lowercase. SHA512 output must be converted with .lower(). Uppercase hash causes payment failure.","severity":"breaking","affected_versions":"all"},{"fix":"Implement reverse hash: salt|status||||||udf5|udf4|...|key and compare with hash returned in PayU callback.","message":"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.","severity":"gotcha","affected_versions":"all"},{"fix":"TEST: POST to https://test.payu.in/_payment. LIVE: POST to https://secure.payu.in/_payment.","message":"Test environment: test.payu.in. Production: secure.payu.in. Using production URL with test keys or vice versa causes connection failure.","severity":"gotcha","affected_versions":"all"},{"fix":"Use UUID: import uuid; txnid = str(uuid.uuid4()).replace('-', '')[:25]","message":"txnid must be unique for every transaction — max 25 chars, alphanumeric. Duplicate txnid causes 'duplicate transaction' error.","severity":"gotcha","affected_versions":"all"},{"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.","message":"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.","severity":"breaking","affected_versions":"all"},{"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`.","message":"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://`).","severity":"breaking","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-05-12T09:47:57.966Z","next_check":"2026-06-25T00:00:00.000Z","problems":[],"ecosystem":"pypi","meta_description":null,"install_score":0,"install_tag":"stale","quickstart_score":0,"quickstart_tag":"stale","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"stale","tag_description":"widespread failures or data too old to trust","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":1,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"stale","tag_description":"widespread failures or data too old to trust","results":[{"runtime":"python:3.10-alpine","exit_code":1},{"runtime":"python:3.10-slim","exit_code":1},{"runtime":"python:3.11-alpine","exit_code":1},{"runtime":"python:3.11-slim","exit_code":1},{"runtime":"python:3.12-alpine","exit_code":1},{"runtime":"python:3.12-slim","exit_code":1},{"runtime":"python:3.13-alpine","exit_code":1},{"runtime":"python:3.13-slim","exit_code":1},{"runtime":"python:3.9-alpine","exit_code":1},{"runtime":"python:3.9-slim","exit_code":1}]}}