{"id":181,"library":"razorpay","title":"Razorpay Python SDK","description":"Official Python SDK for Razorpay — India's leading payment gateway. Current version: 2.0.1 (Mar 2026). Auth uses API key + secret tuple. All amounts in paise (1 INR = 100 paise) — not rupees. Payment flow: create order server-side → collect payment client-side → verify signature server-side. Signature verification is mandatory — skipping it is a security vulnerability. Test keys start with 'rzp_test_', live keys with 'rzp_live_'.","status":"active","version":"2.0.1","language":"python","source_language":"en","source_url":"https://github.com/razorpay/razorpay-python","tags":["razorpay","payments","india","fintech","python","payment-gateway"],"install":[{"cmd":"pip install razorpay","lang":"bash","label":"Python"}],"dependencies":[{"reason":"Required. Installed automatically.","package":"requests","optional":false}],"imports":[{"note":"Amount is always in the smallest currency unit. For INR: paise (1 INR = 100 paise). 500 INR = 50000 paise. Passing rupees directly causes incorrect charges.","wrong":"import razorpay\n\nclient = razorpay.Client(auth=('KEY', 'SECRET'))\n\n# Wrong: amount in rupees\norder = client.order.create({\n    'amount': 500,   # treated as 5 paise, not 500 INR\n    'currency': 'INR'\n})","symbol":"Client + order creation","correct":"import razorpay\n\nclient = razorpay.Client(auth=('rzp_test_KEY', 'SECRET'))\n\n# Amount MUST be in paise — 500 INR = 50000 paise\norder = client.order.create({\n    'amount': 50000,       # 500 INR in paise\n    'currency': 'INR',\n    'receipt': 'order_rcpt_001',\n    'payment_capture': 1   # auto-capture payment\n})\nprint(order['id'])  # pass this to frontend"},{"note":"Signature verification is mandatory. Never fulfill an order based on payment status alone without verifying the HMAC signature. Razorpay raises SignatureVerificationError on failure.","wrong":"# Skipping signature verification — security vulnerability\n# Never trust payment_id from frontend without verifying\npayment = client.payment.fetch(payment_id)\nif payment['status'] == 'captured':\n    fulfill_order()  # could be spoofed","symbol":"verify_payment_signature","correct":"import razorpay\n\nclient = razorpay.Client(auth=('rzp_test_KEY', 'SECRET'))\n\n# After frontend payment — MUST verify signature\nparams = {\n    'razorpay_order_id': order_id,      # from order creation\n    'razorpay_payment_id': payment_id,  # from frontend callback\n    'razorpay_signature': signature     # from frontend callback\n}\n\ntry:\n    client.utility.verify_payment_signature(params)\n    # Signature valid — payment confirmed\n    print('Payment verified')\nexcept razorpay.errors.SignatureVerificationError:\n    # Signature invalid — do NOT fulfill order\n    print('Payment verification failed')"}],"quickstart":{"code":"# pip install razorpay\nimport razorpay\n\n# Use test keys from dashboard.razorpay.com\nclient = razorpay.Client(auth=('rzp_test_YOUR_KEY', 'YOUR_SECRET'))\nclient.enable_retry(True)  # retry on transient failures\n\n# Step 1: Create order server-side\norder = client.order.create({\n    'amount': 50000,    # 500 INR in paise\n    'currency': 'INR',\n    'receipt': 'receipt_001',\n    'notes': {\n        'product': 'Widget',\n        'user_id': '123'\n    }\n})\nprint('Order ID:', order['id'])\n# Pass order['id'], key_id, amount to frontend Razorpay checkout\n\n# Step 2: After frontend payment, verify signature\nparams = {\n    'razorpay_order_id': order['id'],\n    'razorpay_payment_id': 'pay_XXXX',   # from frontend\n    'razorpay_signature': 'SIG_XXXX'     # from frontend\n}\ntry:\n    client.utility.verify_payment_signature(params)\n    print('Payment confirmed')\nexcept razorpay.errors.SignatureVerificationError:\n    print('Invalid signature — reject payment')\n\n# Fetch payment details\npayment = client.payment.fetch('pay_XXXX')\nprint(payment['status'], payment['amount'])\n\n# Refund\nrefund = client.payment.refund('pay_XXXX', {'amount': 50000})\nprint(refund['id'])","lang":"python","description":"Razorpay Python SDK — order creation, signature verification, and refund."},"warnings":[{"fix":"amount_in_paise = amount_in_inr * 100. Always multiply INR by 100.","message":"All amounts are in paise (smallest currency unit) — NOT rupees. 500 INR must be passed as 50000. Passing 500 charges 5 paise (₹0.05). No error is raised — silent wrong charge.","severity":"breaking","affected_versions":"all"},{"fix":"Always call client.utility.verify_payment_signature(params) with razorpay_order_id, razorpay_payment_id, razorpay_signature.","message":"Signature verification is mandatory after payment. Skipping it allows fraudulent payment_id injection. Never fulfill orders without calling verify_payment_signature().","severity":"breaking","affected_versions":"all"},{"fix":"Use environment variables: RAZORPAY_KEY_ID and RAZORPAY_KEY_SECRET. Verify key starts with 'rzp_test_' in development.","message":"Test keys (rzp_test_) and live keys (rzp_live_) are different. Test payments don't transfer real money. Accidentally using live keys in development charges real users.","severity":"gotcha","affected_versions":"all"},{"fix":"client.utility.verify_webhook_signature(payload, signature, WEBHOOK_SECRET) — get WEBHOOK_SECRET from Razorpay dashboard under Webhooks settings.","message":"Webhook signature uses a separate webhook secret — not the API secret. Using API secret for webhook verification raises SignatureVerificationError.","severity":"gotcha","affected_versions":"all"},{"fix":"Add 'payment_capture': 1 to order creation for automatic capture.","message":"payment_capture=1 in order.create auto-captures payment. Without it, payment is authorized but not captured — must manually call client.payment.capture(payment_id, amount).","severity":"gotcha","affected_versions":"all"},{"fix":"client.payment.fetch(), client.order.create(), client.refund.fetch(), client.customer.create()","message":"SDK method naming: client.payment (singular) not client.payments. client.order (singular) not client.orders. Common LLM error.","severity":"gotcha","affected_versions":"all"},{"fix":"Use currency='INR' for standard integration. Contact Razorpay for international payment activation.","message":"Razorpay only supports INR for domestic payments. International currencies require Razorpay's international payment product with separate activation.","severity":"gotcha","affected_versions":"all"},{"fix":"Ensure that RAZORPAY_KEY_ID and RAZORPAY_KEY_SECRET are correctly obtained from your Razorpay dashboard and properly configured in your application (e.g., via environment variables or direct instantiation of razorpay.Client).","message":"The 'Authentication failed' error means your API Key ID or Secret is incorrect or missing. Verify that both RAZORPAY_KEY_ID and RAZORPAY_KEY_SECRET are accurately set and passed to the Razorpay client.","severity":"breaking","affected_versions":"all"},{"fix":"Ensure RAZORPAY_KEY_ID and RAZORPAY_KEY_SECRET environment variables are set correctly with valid API keys. Double-check for typos and confirm the keys are active and have the necessary permissions in your Razorpay dashboard.","message":"The API keys (RAZORPAY_KEY_ID and RAZORPAY_KEY_SECRET) are either incorrect, missing, or have insufficient permissions, leading to an 'Authentication failed' error. This is a fundamental issue preventing any API interaction.","severity":"breaking","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-05-12T09:47:01.026Z","next_check":"2026-06-25T00:00:00.000Z","problems":[],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":0,"quickstart_tag":"stale","pypi_latest":null,"cli_name":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.59,"mem_mb":9.9,"disk_size":"21.8M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.42,"mem_mb":9.9,"disk_size":"22M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.78,"mem_mb":11.1,"disk_size":"23.9M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.63,"mem_mb":11.1,"disk_size":"24M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.7,"mem_mb":11.6,"disk_size":"15.6M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.69,"mem_mb":11.6,"disk_size":"16M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.67,"mem_mb":11.9,"disk_size":"15.3M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.67,"mem_mb":11.9,"disk_size":"16M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.54,"mem_mb":9.7,"disk_size":"21.0M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.47,"mem_mb":9.7,"disk_size":"22M"}]},"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}]}}