Razorpay Python Client

repository·master·Indexed 41 days ago

https://github.com/razorpay/razorpay-python

Python bindings for the Razorpay API, enabling merchants to programmatically manage payments, orders, customers, and other resources. The client provides functionality for sub-merchant account management, subscription addons, card payments, registration links, customer bank account linking, eligibility checks, and POS device activity management.

Tokens
49.8K
Snippets
224
Records
238
Agent score
51%

What's inside Razorpay

  1. Integrate Device Activity with Order APIs

    master

    For a complete POS workflow, create a Razorpay Order first, then use that order_id to initiate the device activity. This ensures the transaction is linked to a valid order in the Razorpay dashboard.

    # Create order with device_mode
    order = client.order.create({
        "amount": 50000,
        "currency": "INR",
        "receipt": "order_001"
    }, device_mode="wired")
    
    # Initiate device checkout using the created order ID
    checkout = client.device_activity.create({
        "device_id": "2841158834",
        "action": "initiate_checkout",
        "notes": {"order_id": order['id']},
        "initiate_checkout": {
            "name": "Acme Corp",
            "amount": order['amount'],
            "currency": order['currency'],
            "description": "POS Transaction",
            "type": "in_person",
            "order_id": order['id'],
            "prefill": {
                "method": "upi"
            }
        }
    }, device_mode="wired")
  2. Implement Retry Logic for POS Operations

    master

    For transient errors like DEVICE_BUSY, DEVICE_TIMEOUT, or DEVICE_DISCONNECTED, it is recommended to implement an exponential backoff retry strategy to improve reliability.

    import time
    
    def retry_device_operation(operation_func, max_retries=3):
        for attempt in range(max_retries):
            try:
                return operation_func()
            except Exception as e:
                error_code = getattr(e, 'code', None)
                
                # Retry for transient errors
                if error_code in ['DEVICE_BUSY', 'DEVICE_TIMEOUT', 'DEVICE_DISCONNECTED']:
                    if attempt < max_retries - 1:
                        time.sleep(2 ** attempt)  # Exponential backoff
                        continue
                raise e
  3. Initialize the Razorpay POS Gateway client

    master

    To integrate with the POS Gateway, initialize the razorpay.Client using your key_id and key_secret.

    For production, the default base_url is https://api.razorpay.com. For local development or testing with a POS Gateway simulator, you must specify the base_url pointing to your local host.

    import razorpay
    
    # Production initialization
    client = razorpay.Client(auth=('your_key_id', 'your_key_secret'))
    
    # Local development/testing initialization
    client = razorpay.Client(
        auth=('your_key_id', 'your_key_secret'),
        base_url='http://localhost:PORT'
    )
  4. Initialize the Razorpay Client

    master

    To use the client, import razorpay and initialize the razorpay.Client using your API Key and API Secret. You can find these credentials in your Razorpay Dashboard at https://dashboard.razorpay.com/#/app/keys.

    You can also enable the retry mechanism for failed API calls using client.enable_retry(True).

    import razorpay
    client = razorpay.Client(auth=("<YOUR_API_KEY>", "<YOUR_API_SECRET>"))
    
    client.enable_retry(True)  # Enable retry mechanism for failed API calls
  5. Handle API response status for checkouts

    master

    After initiating a checkout via the Device Activity API, you should check the status field in the response to determine the next steps for your application flow.

    Possible statuses:

    • processing: Checkout has been initiated; wait for completion.
    • completed: Checkout was successful.
    • failed: Checkout failed. You should inspect the error object for the code and reason to understand why.
    # Check status in response
    if response['status'] == 'processing':
        print("Checkout initiated, waiting for completion...")
    elif response['status'] == 'completed':
        print("Checkout completed successfully!")
    elif response['status'] == 'failed':
        error_code = response['error']['code']
        error_reason = response['error']['reason']
        print(f"Checkout failed: {error_code} - {error_reason}")
  6. Handle Card OTP (Generate and Submit)

    master

    For card authentication, follow the OTP lifecycle:

    1. Generate OTP: Call client.payment.otpGenerate(paymentId) to get the required actions (e.g., otp_submit, otp_resend).
    2. Submit OTP: Call client.payment.otpSubmit(paymentId, {"otp": "..."}) with the customer's OTP to complete the transaction.
    # 1. Generate
    client.payment.otpGenerate(paymentId)
    
    # 2. Submit
    client.payment.otpSubmit(paymentId, {
     	"otp": "12345"
     })
  7. Handle POS Gateway API errors in Python

    master

    When working with the POS Gateway, you should handle errors using specific exception classes like BadRequestError from razorpay.errors. You can inspect the error message to provide specific guidance to users, such as correcting the device_mode or providing valid activity data.

    Common error scenarios include:

    • Invalid device mode: Ensure you use either "wired" or "wireless".
    • device_id required for wireless mode: If using device_mode="wireless", you must include a device_id in your request.
    from razorpay.errors import BadRequestError
    
    try:
        response = client.device_activity.create(data, device_mode="wired")
    except BadRequestError as e:
        if "Invalid device mode" in str(e):
            print("Use 'wired' or 'wireless' for device_mode")
        elif "Invalid activity data" in str(e):
            print("Provide valid activity data")
        else:
            print(f"API Error: {e}")
    except Exception as e:
        print(f"Unexpected error: {e}")
  8. Handle Device Activity errors

    master

    When interacting with Device Activity APIs, you may encounter BadRequestError or specific API error codes in the response.

    Common Client-Side Errors:

    • BadRequestError: Occurs if device_mode is invalid (must be wired or wireless) or if device_id is missing while in wireless mode.

    API Error Codes (returned in response):

    • BAD_REQUEST_ERROR with reason device_not_connected: The device is not currently connected. Check connection and retry.
    • BAD_REQUEST_ERROR with reason checkout_not_found: The session was not found. Ensure a checkout was successfully initiated before attempting to close it.
    from razorpay.errors import BadRequestError
    
    try:
        response = client.device_activity.create({
            "device_id": "2841158834",
            "action": "initiate_checkout"
        }, device_mode="invalid_mode")
    except BadRequestError as e:
        print(f"Error: {e}")
  9. Complete POS Integration Workflow Example

    master

    A standard end-to-end workflow involves two main steps:

    1. Create an Order: Generate a unique order in the system.
    2. Initiate Device Checkout: Use the order ID to trigger the physical POS device to start the payment process.

    Finally, it is good practice to call close_checkout to clean up the session.

    import razorpay
    import time
    
    class POSIntegration:
        def __init__(self, key_id, key_secret, base_url=None):
            self.client = razorpay.Client(auth=(key_id, key_secret), base_url=base_url)
    
        def complete_pos_checkout(self, device_id, amount, device_mode="wired"):
            try:
                # Step 1: Create Order
                order = self.client.order.create({
                    "amount": amount,
                    "currency": "INR",
                    "receipt": f"pos_order_{int(time.time())}",
                    "notes": {"device_id": device_id}
                }, device_mode=device_mode)
                
                # Step 2: Initiate Device Checkout
                activity = self.client.device_activity.create({
                    "device_id": device_id,
                    "action": "initiate_checkout",
                    "notes": {"order_id": order['id']},
                    "initiate_checkout": {
                        "name": "Acme Corp",
                        "amount": amount,
                        "currency": "INR",
                        "description": "POS Transaction",
                        "type": "in_person",
                        "order_id": order['id'],
                        "prefill": {
                            "name": "Customer Name",
                            "email": "customer@example.com",
                            "contact": "9000090000",
                            "method": "upi"
                        }
                    }
                }, device_mode=device_mode)
                
                self.close_checkout(device_id, device_mode)
                return {"success": True, "order": order, "activity": activity}
            except Exception as e:
                return {"success": False, "error": str(e)}
    
        def close_checkout(self, device_id, device_mode):
            try:
                return self.client.device_activity.create({
                    "device_id": device_id,
                    "action": "close_checkout"
                }, device_mode=device_mode)
            except Exception as e:
                print(f"Failed to close checkout: {e}")
                return None
    
    # Usage
    pos = POSIntegration('your_key_id', 'your_key_secret')
    result = pos.complete_pos_checkout(device_id="2841158834", amount=19900, device_mode="wired")