|
| 1 | +--- |
| 2 | +title: A simple step-by-step guide to integrate mobile money payments for your python web application in Cameroun (2024) |
| 3 | +date: '2024-09-07' |
| 4 | +tags: ['Payment API', 'Mobile Money', 'Python'] |
| 5 | +draft: false |
| 6 | +summary: 3 simple steps to integrate mobile money payment into your Python web application |
| 7 | +images: [] |
| 8 | +layout: PostLayout |
| 9 | +canonicalUrl: mobile-money-integration-python-cameroon-2024 |
| 10 | +authors: ['nab'] |
| 11 | +--- |
| 12 | + |
| 13 | +This is a translation of an article I wrote in January 2024. In that article, i'm explaining how to integrate Orange Money or MTN Momo in a python web application. Just for you to know, i wrote that article because i wanted to share with every developer in Cameroon, the steps i did follow to integrate a mobile money payment provider to my marketplace. I found that platform really simple, so, let's get started. |
| 14 | + |
| 15 | +[Notchpay](https://notchpay.co/) offers you a way to integrate payment methods into your application and supports card and mobile money payments. |
| 16 | + |
| 17 | +The integration is simple: |
| 18 | + |
| 19 | +First, create an account on [Notchpay](https://business.notchpay.co/). Your account gives you access to a sandbox that allows you to test the API. In the **settings** (Settings > Developer), you'll find your **API key** (PUBLIC_KEY) that you'll use for authentication in your application. |
| 20 | + |
| 21 | +## Initiating payment |
| 22 | + |
| 23 | +The [documentation](https://developer.notchpay.co/) already describe all the endpoints you can use, particularly in the [API reference](https://developer.notchpay.co/api/tag/payment) section. |
| 24 | + |
| 25 | +In our case, we will use [Flask](https://pypi.org/project/Flask/) to build the controllers and the [Requests](https://pypi.org/project/requests/) library to make requests to Notchpay. |
| 26 | + |
| 27 | +Let's first initialize the payment: |
| 28 | + |
| 29 | +```python |
| 30 | +def initialize_payment( |
| 31 | + email, currency, amount, phone, reference, description, callback |
| 32 | +): |
| 33 | + headers = {"Authorization": PUBLIC_KEY, "Accept": "application/json"} |
| 34 | + url = "https://api.notchpay.co/payments/initialize" |
| 35 | + data = { |
| 36 | + "email": email, |
| 37 | + "currency": currency, |
| 38 | + "amount": amount, |
| 39 | + "phone": phone, |
| 40 | + "reference": reference, |
| 41 | + "description": description, |
| 42 | + "callback": callback, |
| 43 | + } |
| 44 | + |
| 45 | + response = requests.post(url, headers=headers, data=data) |
| 46 | + |
| 47 | + if response.ok: |
| 48 | + json_response = response.json() |
| 49 | + return json_response |
| 50 | + else: |
| 51 | + return {"status_code": response.status_code, "msg": response.text} |
| 52 | +``` |
| 53 | + |
| 54 | +In that function: |
| 55 | + |
| 56 | +1. We define the necessary data for the payment as arguments, in the **data** variable, |
| 57 | +2. Then the **header** through which we execute our request. This header contains the API Key |
| 58 | +3. And we return a JSON response. |
| 59 | + |
| 60 | +For more information on this payment initiation endpoint and the JSON response, just go to the documentation of that endpoint [/payments/initialize](https://developer.notchpay.co/api/tag/payment/post/payments) |
| 61 | + |
| 62 | +Additionally, note that the callback will be a controller on your site that will be called after the payment. You can use it to implement payment verification. |
| 63 | + |
| 64 | +- From there, we'll create our controllers: first a simple web page that displays a "Pay Now" link. |
| 65 | +- When this link is clicked, the **pay()** controller is called and will initiate the payment then will do a redirection to the Notchpay payment page: |
| 66 | + |
| 67 | +```python |
| 68 | +return redirect(init_payment.get("authorization_url")) |
| 69 | +``` |
| 70 | + |
| 71 | +- At this point, the Notchpay page dedicated for the payment will be displayed |
| 72 | +- The user can then make his payment via credit card or mobile money phone number |
| 73 | + |
| 74 | +```python |
| 75 | +HTML_PAGE = """ |
| 76 | +<h1>Process payment</h1> |
| 77 | +<a href="/pay">Pay Now</a> |
| 78 | +""" |
| 79 | + |
| 80 | +@app.route("/") |
| 81 | +def home(): |
| 82 | + return HTML_PAGE |
| 83 | + |
| 84 | +@app.route("/pay") |
| 85 | +def pay(): |
| 86 | + payment_reference = uuid.uuid1() |
| 87 | + init_payment = initialize_payment( |
| 88 | + |
| 89 | + currency="XAF", |
| 90 | + amount="1500", |
| 91 | + phone=None, |
| 92 | + reference=payment_reference, |
| 93 | + description=f"Payment description {payment_reference}", |
| 94 | + callback=f"http://localhost:5000/verify", # make sure to have the right host |
| 95 | + ) |
| 96 | + return redirect(init_payment.get("authorization_url")) |
| 97 | +``` |
| 98 | + |
| 99 | +When the payment is made by the user, it must then be verified through the callback that was passed to the **initialize_payment()** function. |
| 100 | + |
| 101 | +## Payment verification |
| 102 | + |
| 103 | +Here is the verification function : |
| 104 | + |
| 105 | +```python |
| 106 | +def verify_payment(reference): |
| 107 | + url = f"https://api.notchpay.co/payments/{reference}" |
| 108 | + headers = {"Authorization": PUBLIC_KEY} |
| 109 | + |
| 110 | + response = requests.get(url, headers=headers) |
| 111 | + |
| 112 | + if response.ok: |
| 113 | + json_response = response.json() |
| 114 | + logger.debug(json_response) |
| 115 | + return json_response |
| 116 | + else: |
| 117 | + return {"status_code": response.status_code, "msg": response.text} |
| 118 | +``` |
| 119 | + |
| 120 | +1. This function takes as parameter the payment reference which is passed in the callback via a **GET** method from Notchpay. |
| 121 | +2. We then construct the header through the URL [/payments/{reference}](https://developer.notchpay.co/reference/payments#verify-and-fetch-payment) for payment verification |
| 122 | +3. and return a JSON response |
| 123 | + |
| 124 | +The callback will be the **verify()** controller which will extract the reference and pass this payment reference to the **verify_payment()** function |
| 125 | + |
| 126 | +```python |
| 127 | +@app.route("/verify") |
| 128 | +def verify(): |
| 129 | + reference = request.args.get("reference") |
| 130 | + return verify_payment(reference) |
| 131 | +``` |
| 132 | + |
| 133 | +From there, you can just retrieve the JSON response to continue your process based on the response (payment failure or success) |
| 134 | + |
| 135 | +## Payment verification through a Webhook |
| 136 | + |
| 137 | +If you want to verify payments in the background, you can set up a webhook in your backend like this: |
| 138 | + |
| 139 | +```python |
| 140 | +@app.route("/webhook", methods=["POST"]) |
| 141 | +def webhook(): |
| 142 | + signature = request.headers.get("x-notch-signature") |
| 143 | + hash_value = hashlib.sha256(HASH_KEY).hexdigest() |
| 144 | + if hash_value == signature: |
| 145 | + try: |
| 146 | + json_data = request.get_json() |
| 147 | + logger.info("Webhook data:", json_data) |
| 148 | + return "", 200 # OK |
| 149 | + except Exception as e: |
| 150 | + logger.info("Error parsing JSON:", e) |
| 151 | + abort(400) # Bad request |
| 152 | + else: |
| 153 | + logger.info("Webhook request could not be verified.") |
| 154 | + abort(403) # Forbidden |
| 155 | +``` |
| 156 | + |
| 157 | +Notchpay will then send the response of each payment to your webhook and depending on the result, you can continue your process, such as validating an order for example. |
| 158 | + |
| 159 | +If you're on localhost, you'll need to install [Ngrok](https://ngrok.com/) to make your URL public and go to the Notchpay administration interface to define your webhook with a key and your URL. |
| 160 | + |
| 161 | +The key will be the one you will use as **HASH_KEY** to authenticate your server so that Notchpay recognizes your signature. |
| 162 | + |
| 163 | +That's all for now. |
| 164 | + |
| 165 | +You can find the complete code [here on GitHub](https://github.com/abdounasser202/just-for-fun/tree/main/notchpay) |
| 166 | + |
| 167 | +If you have any questions, don't hesitate to ask in the OSS Telegram Channel. |
| 168 | + |
| 169 | +Ciao ! |
0 commit comments