Skip to content
This repository was archived by the owner on Jul 7, 2025. It is now read-only.

Commit 6f08e9c

Browse files
committed
v1.0.0 - charge api
1 parent 41434b0 commit 6f08e9c

File tree

10 files changed

+246
-271
lines changed

10 files changed

+246
-271
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
strategy:
1414
fail-fast: false
1515
matrix:
16-
python-version: ["3.7", "3.8", "3.9", "3.10"]
16+
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
1717

1818
steps:
1919
- uses: actions/checkout@v2

README.md

Lines changed: 1 addition & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,135 +1 @@
1-
# Python Flutterwave
2-
3-
### Description
4-
Python Wrapper for interacting with the Flutterwave API
5-
6-
7-
### Contribution
8-
- Before making any further steps (for interested contributors), please refer to the [CONTRIBUTING GUIDE](/CONTRIBUTING.md).
9-
10-
11-
## Installation
12-
13-
- ``pip install python-flutterwave``
14-
15-
## Usage
16-
17-
- Create an account in Flutterwave [here](https://dashboard.flutterwave.com/signup?referrals=RV1284343) and obtain your `Secret Key` only.
18-
19-
```
20-
from python_flutterwave import payment
21-
22-
payment.token = 'YOUR_SECRET_KEY'
23-
```
24-
25-
```
26-
Here are all the possible values for payment options available on Flutterwave:
27-
0: "account"
28-
1: "card"
29-
2: "banktransfer"
30-
3: "mpesa"
31-
4: "mobilemoneyrwanda"
32-
5: "mobilemoneyzambia"
33-
6: "qr"
34-
7: "mobilemoneyuganda"
35-
8: "ussd"
36-
9: "credit"
37-
10: "barter"
38-
11: "mobilemoneyghana"
39-
12: "payattitude"
40-
13: "mobilemoneyfranco"
41-
14: "paga"
42-
15: "1voucher"
43-
16: "mobilemoneytanzania"
44-
```
45-
46-
- To trigger a standard payment that returns a redirect uri
47-
48-
```python
49-
uri = payment.initiate_payment(tx_ref="qwerty", amount=100, redirect_url='your_callback_url',
50-
payment_options='mpesa', customer_email='example@email.com',
51-
customer_phone_number='0123456789', currency='KES', customer_name='John Doe',
52-
title='Demo Payment', description='Just pay me...')
53-
print(uri)
54-
```
55-
- Redirect the user to that uri where he/she will make the payment.
56-
- After payment is made, the user will be redirected to the `redirect_url` you declared but Flutterwave will append some
57-
info regarding the payment i.e. `transaction_id` and `tx_ref`. If your url is `https://example.com/callback`
58-
then it may be `http://example.com/callback/?status=successful&tx_ref=qwerty&transaction_id=2784792`
59-
- You should save the transaction_id to your DB as it will be used to query the transaction details.
60-
61-
> There is no need to save the transaction_id as it is also possible to use tx_ref to get the payment details!
62-
> Check here - https://developer.flutterwave.com/reference/endpoints/transactions/
63-
64-
65-
- To check the transaction details e.g. successful or not, grab the transaction_id from the previous step.
66-
```python
67-
details = payment.get_payment_details(transaction_id)
68-
# or
69-
deailts = payment.get_payment_details_via_tx_ref(tx_ref)
70-
71-
print(details)
72-
```
73-
74-
- To trigger an automatic MPESA charge on your customer through STK push, first configure your Webhook url in the dashboard, it may be a
75-
simple server; Flutterwave will post some data regarding your transaction status in that url. This method call will
76-
return a Python dict object. You can decide what to do thereon.
77-
```python
78-
mpesa_trans_details = payment.trigger_mpesa_payment(tx_ref="qwertyuio", amount=100, currency='KES',
79-
email='johndoe@gmail.com', phone_number='1234567890',
80-
full_name='John Doe')
81-
print(mpesa_trans_details)
82-
```
83-
84-
- To initiate a USSD payment to your customer, configure your webhook url in the dashboard where Flutterwave will post data
85-
regarding the transaction. This method call will return a Python Dict object from which you can extract the USSD code to
86-
show your customer for payment completion. For other banks, you may also need to extract the `payment_code` from the result.
87-
88-
- By default, `NGN` is the only supported currency for USSD payments so this method automatically uses `NGN`
89-
- Only a number of banks support `USSD` so you have to refer to the docs to check your bank and its corresponding `account_bank` code.
90-
```
91-
At the moment, banks available for USSD payments (and their numeric codes) are:
92-
93-
Access Bank -- 044
94-
Ecobank -- 050
95-
Fidelity Bank -- 070
96-
First Bank of Nigeria -- 011
97-
First City Monument Bank (FCMB) -- 214
98-
GTBank -- 058
99-
Heritage Bank -- 030
100-
Keystone Bank -- 082
101-
Stanbic IBTC Bank -- 221
102-
Sterling Bank -- 232
103-
Union Bank -- 032
104-
United Bank for Africa -- 033
105-
Unity Bank -- 215
106-
VFD Microfinance Bank -- 090110
107-
Wema Bank -- 035
108-
Zenith Bank -- 057
109-
```
110-
111-
112-
```python
113-
details = payment.initiate_ussd_payment(tx_ref="123erd", amount=100, email='johndoe@gmail.com',
114-
phone_number='789456123', full_name='John Doe', account_bank='057')
115-
print(details)
116-
```
117-
118-
- For bank transactions, it is important to first verify the details given to you by the customer before granting incentives
119-
according to the specifications of your application.
120-
- To verify bank details call the function below that returns a Python dictionary with the data...
121-
```python
122-
details = payment.verify_bank_account_details(account_number= "0690000032", account_bank= "044")
123-
print(details)
124-
```
125-
126-
- For card transactions, it is advisable to ascertain the customer's card details before granting incentives according
127-
to the specifications of your application.
128-
- This function call takes the `card_bin` (usually the first 4-6 digits in debit/credit cards) and returns info regarding
129-
the card. A Python dict object is returned, thence use it according to your needs.
130-
```python
131-
details = payment.verify_card_details(card_bin=553188)
132-
print(details)
133-
```
134-
135-
[![Sponsor Python Flutterwave](https://cdn.buymeacoffee.com/buttons/default-red.png)](https://dashboard.flutterwave.com/donate/zvapzky1ozls)
1+
```New docs under development```
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from .bank import *
2+
from .card import *
3+
from .mobile import *
4+
from .validation import *
5+

python_flutterwave/charge/bank.py

Lines changed: 6 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
import requests
33
import json
44

5-
from python_flutterwave.exceptions import TokenException
5+
from python_flutterwave.decorators import handle_api_exceptions
66

77

88
token = os.environ.get("SECRET_KEY")
99
base_url = "https://api.flutterwave.com/v3/charges"
1010

1111

12+
@handle_api_exceptions
1213
def initiate_bank_charge(
1314
amount: int,
1415
email: str,
@@ -22,9 +23,6 @@ def initiate_bank_charge(
2223
:return: dict
2324
"""
2425

25-
if token == "" or token is None:
26-
raise TokenException(token=token, message="Authentication token absent")
27-
2826
params = {"type": "bank_transfer"}
2927
payload = json.dumps(
3028
{
@@ -36,16 +34,11 @@ def initiate_bank_charge(
3634
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
3735

3836
response = requests.post(url=base_url, headers=headers, data=payload, params=params)
39-
if response.status_code == 401:
40-
raise TokenException(token=token, message="Invalid token provided")
41-
if response.status_code == 400:
42-
raise Exception(f"{response.json()['message']}")
43-
if response.status_code >= 400:
44-
raise Exception(response.text)
4537

4638
return dict(response.json())
4739

4840

41+
@handle_api_exceptions
4942
def initiate_nigeria_bank_charge(
5043
amount: int,
5144
email: str,
@@ -59,9 +52,6 @@ def initiate_nigeria_bank_charge(
5952
:return: dict
6053
"""
6154

62-
if token == "" or token is None:
63-
raise TokenException(token=token, message="Authentication token absent")
64-
6555
params = {"type": "mono"}
6656
payload = json.dumps(
6757
{
@@ -73,16 +63,11 @@ def initiate_nigeria_bank_charge(
7363
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
7464

7565
response = requests.post(url=base_url, headers=headers, data=payload, params=params)
76-
if response.status_code == 401:
77-
raise TokenException(token=token, message="Invalid token provided")
78-
if response.status_code == 400:
79-
raise Exception(f"{response.json()['message']}")
80-
if response.status_code >= 400:
81-
raise Exception(response.text)
8266

8367
return dict(response.json())
8468

8569

70+
@handle_api_exceptions
8671
def initiate_uk_eu_bank_charge(
8772
amount: int, email: str, tx_ref: str, phone_number: str, is_token_io: int
8873
) -> dict:
@@ -96,9 +81,6 @@ def initiate_uk_eu_bank_charge(
9681
:return: dict
9782
"""
9883

99-
if token == "" or token is None:
100-
raise TokenException(token=token, message="Authentication token absent")
101-
10284
params = {"type": "account-ach-uk"}
10385
payload = json.dumps(
10486
{
@@ -112,17 +94,12 @@ def initiate_uk_eu_bank_charge(
11294
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
11395

11496
response = requests.post(url=base_url, headers=headers, data=payload, params=params)
115-
if response.status_code == 401:
116-
raise TokenException(token=token, message="Invalid token provided")
117-
if response.status_code == 400:
118-
raise Exception(f"{response.json()['message']}")
119-
if response.status_code >= 400:
120-
raise Exception(response.text)
12197

12298
return dict(response.json())
12399

124100

125-
def initiate_ach_charge(
101+
@handle_api_exceptions
102+
def initiate_ach_bank_charge(
126103
amount: int,
127104
email: str,
128105
tx_ref: str,
@@ -139,9 +116,6 @@ def initiate_ach_charge(
139116
:return: dict
140117
"""
141118

142-
if token == "" or token is None:
143-
raise TokenException(token=token, message="Authentication token absent")
144-
145119
params = {"type": "account-ach-uk"}
146120
payload = json.dumps(
147121
{
@@ -155,11 +129,5 @@ def initiate_ach_charge(
155129
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
156130

157131
response = requests.post(url=base_url, headers=headers, data=payload, params=params)
158-
if response.status_code == 401:
159-
raise TokenException(token=token, message="Invalid token provided")
160-
if response.status_code == 400:
161-
raise Exception(f"{response.json()['message']}")
162-
if response.status_code >= 400:
163-
raise Exception(response.text)
164132

165133
return dict(response.json())

python_flutterwave/charge/card.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
import requests
33
import json
44

5-
from python_flutterwave.exceptions import TokenException
5+
from python_flutterwave.decorators import handle_api_exceptions
66

77

88
token = os.environ.get("SECRET_KEY")
99
base_url = "https://api.flutterwave.com/v3/charges"
1010

1111

12+
@handle_api_exceptions
1213
def initiate_card_charge(
1314
amount: int,
1415
card_number: int,
@@ -30,9 +31,6 @@ def initiate_card_charge(
3031
:return: dict
3132
"""
3233

33-
if token == "" or token is None:
34-
raise TokenException(token=token, message="Authentication token absent")
35-
3634
params = {"type": "card"}
3735
payload = json.dumps(
3836
{
@@ -48,11 +46,5 @@ def initiate_card_charge(
4846
headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
4947

5048
response = requests.post(url=base_url, headers=headers, data=payload, params=params)
51-
if response.status_code == 401:
52-
raise TokenException(token=token, message="Invalid token provided")
53-
if response.status_code == 400:
54-
raise Exception(f"{response.json()['message']}")
55-
if response.status_code >= 400:
56-
raise Exception(response.text)
5749

5850
return dict(response.json())

0 commit comments

Comments
 (0)