zarpay 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
zarpay-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ZarPay
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
zarpay-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,146 @@
1
+ Metadata-Version: 2.4
2
+ Name: zarpay
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for the ZarPay payment gateway
5
+ Home-page: https://github.com/zarpay/zarpay-python
6
+ Author: ZarPay
7
+ Author-email: support@zarpay.pk
8
+ License: MIT
9
+ Keywords: zarpay,payments,jazzcash,easypaisa,pakistan
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: >=3.8
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: requests>=2.20.0
17
+ Dynamic: author
18
+ Dynamic: author-email
19
+ Dynamic: classifier
20
+ Dynamic: description
21
+ Dynamic: description-content-type
22
+ Dynamic: home-page
23
+ Dynamic: keywords
24
+ Dynamic: license
25
+ Dynamic: license-file
26
+ Dynamic: requires-dist
27
+ Dynamic: requires-python
28
+ Dynamic: summary
29
+
30
+ # ZarPay Python SDK
31
+
32
+ Official Python SDK for the [ZarPay](https://zarpay.pk) payment gateway.
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ pip install zarpay
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ```python
43
+ from zarpay import ZarPay
44
+
45
+ client = ZarPay("sk_sandbox_xxxxxxxxxxxxx")
46
+
47
+ payment = client.payments.create(
48
+ merchant_order_id="ORD-123",
49
+ amount=1500,
50
+ channel_id=1,
51
+ customer_phone="03001234567",
52
+ )
53
+
54
+ print(payment["data"]["status"]) # 'completed' | 'processing' | 'failed'
55
+ ```
56
+
57
+ ## Usage
58
+
59
+ ### List Available Channels
60
+
61
+ ```python
62
+ channels = client.channels.list()
63
+
64
+ for ch in channels["data"]["channels"]:
65
+ print(f"{ch['id']}: {ch['wallet_type']}")
66
+ ```
67
+
68
+ ### Create a Payment
69
+
70
+ ```python
71
+ payment = client.payments.create(
72
+ merchant_order_id="ORD-456",
73
+ amount=2500,
74
+ channel_id=1,
75
+ customer_phone="03001234567",
76
+ metadata={"customer_name": "Ahmed Khan"},
77
+ idempotency_key="unique-key-456",
78
+ )
79
+
80
+ if payment["success"]:
81
+ print("Payment completed:", payment["data"]["zarpay_id"])
82
+ else:
83
+ print("Payment failed:", payment["data"]["failure_reason"])
84
+ ```
85
+
86
+ ### Get Payment Status
87
+
88
+ ```python
89
+ # By ZarPay ID
90
+ payment = client.payments.get("ZP_abc123def456")
91
+
92
+ # By your order ID
93
+ payment = client.payments.get_by_order_id("ORD-456")
94
+ ```
95
+
96
+ ### Verify Webhooks
97
+
98
+ ```python
99
+ from zarpay import verify_webhook
100
+
101
+ # In your webhook handler (e.g. Flask/Django)
102
+ def webhook_handler(request):
103
+ try:
104
+ event = verify_webhook(
105
+ raw_body=request.body,
106
+ signature_header=request.headers["X-ZarPay-Signature"],
107
+ secret="whsec_your_webhook_secret",
108
+ )
109
+
110
+ if event["event"] == "payment.completed":
111
+ # Fulfill the order
112
+ pass
113
+ elif event["event"] == "payment.failed":
114
+ # Notify customer
115
+ pass
116
+
117
+ return HttpResponse(status=200)
118
+ except ValueError:
119
+ return HttpResponse(status=400)
120
+ ```
121
+
122
+ ### Error Handling
123
+
124
+ ```python
125
+ from zarpay import ZarPay, ZarPayAPIError
126
+
127
+ try:
128
+ payment = client.payments.create(...)
129
+ except ZarPayAPIError as e:
130
+ print(e.status_code) # 400, 401, 409, etc.
131
+ print(e.error) # Human-readable error message
132
+ ```
133
+
134
+ ### Configuration
135
+
136
+ ```python
137
+ client = ZarPay(
138
+ "sk_sandbox_xxx",
139
+ base_url="http://localhost:3000/api/v1", # local development
140
+ timeout=60, # seconds
141
+ )
142
+ ```
143
+
144
+ ## License
145
+
146
+ MIT
zarpay-1.0.0/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # ZarPay Python SDK
2
+
3
+ Official Python SDK for the [ZarPay](https://zarpay.pk) payment gateway.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install zarpay
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```python
14
+ from zarpay import ZarPay
15
+
16
+ client = ZarPay("sk_sandbox_xxxxxxxxxxxxx")
17
+
18
+ payment = client.payments.create(
19
+ merchant_order_id="ORD-123",
20
+ amount=1500,
21
+ channel_id=1,
22
+ customer_phone="03001234567",
23
+ )
24
+
25
+ print(payment["data"]["status"]) # 'completed' | 'processing' | 'failed'
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ ### List Available Channels
31
+
32
+ ```python
33
+ channels = client.channels.list()
34
+
35
+ for ch in channels["data"]["channels"]:
36
+ print(f"{ch['id']}: {ch['wallet_type']}")
37
+ ```
38
+
39
+ ### Create a Payment
40
+
41
+ ```python
42
+ payment = client.payments.create(
43
+ merchant_order_id="ORD-456",
44
+ amount=2500,
45
+ channel_id=1,
46
+ customer_phone="03001234567",
47
+ metadata={"customer_name": "Ahmed Khan"},
48
+ idempotency_key="unique-key-456",
49
+ )
50
+
51
+ if payment["success"]:
52
+ print("Payment completed:", payment["data"]["zarpay_id"])
53
+ else:
54
+ print("Payment failed:", payment["data"]["failure_reason"])
55
+ ```
56
+
57
+ ### Get Payment Status
58
+
59
+ ```python
60
+ # By ZarPay ID
61
+ payment = client.payments.get("ZP_abc123def456")
62
+
63
+ # By your order ID
64
+ payment = client.payments.get_by_order_id("ORD-456")
65
+ ```
66
+
67
+ ### Verify Webhooks
68
+
69
+ ```python
70
+ from zarpay import verify_webhook
71
+
72
+ # In your webhook handler (e.g. Flask/Django)
73
+ def webhook_handler(request):
74
+ try:
75
+ event = verify_webhook(
76
+ raw_body=request.body,
77
+ signature_header=request.headers["X-ZarPay-Signature"],
78
+ secret="whsec_your_webhook_secret",
79
+ )
80
+
81
+ if event["event"] == "payment.completed":
82
+ # Fulfill the order
83
+ pass
84
+ elif event["event"] == "payment.failed":
85
+ # Notify customer
86
+ pass
87
+
88
+ return HttpResponse(status=200)
89
+ except ValueError:
90
+ return HttpResponse(status=400)
91
+ ```
92
+
93
+ ### Error Handling
94
+
95
+ ```python
96
+ from zarpay import ZarPay, ZarPayAPIError
97
+
98
+ try:
99
+ payment = client.payments.create(...)
100
+ except ZarPayAPIError as e:
101
+ print(e.status_code) # 400, 401, 409, etc.
102
+ print(e.error) # Human-readable error message
103
+ ```
104
+
105
+ ### Configuration
106
+
107
+ ```python
108
+ client = ZarPay(
109
+ "sk_sandbox_xxx",
110
+ base_url="http://localhost:3000/api/v1", # local development
111
+ timeout=60, # seconds
112
+ )
113
+ ```
114
+
115
+ ## License
116
+
117
+ MIT
@@ -0,0 +1,3 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "wheel"]
3
+ build-backend = "setuptools.build_meta"
zarpay-1.0.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
zarpay-1.0.0/setup.py ADDED
@@ -0,0 +1,22 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="zarpay",
5
+ version="1.0.0",
6
+ description="Official Python SDK for the ZarPay payment gateway",
7
+ long_description=open("README.md").read(),
8
+ long_description_content_type="text/markdown",
9
+ author="ZarPay",
10
+ author_email="support@zarpay.pk",
11
+ url="https://github.com/zarpay/zarpay-python",
12
+ packages=find_packages(),
13
+ python_requires=">=3.8",
14
+ install_requires=["requests>=2.20.0"],
15
+ keywords=["zarpay", "payments", "jazzcash", "easypaisa", "pakistan"],
16
+ license="MIT",
17
+ classifiers=[
18
+ "Programming Language :: Python :: 3",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Operating System :: OS Independent",
21
+ ],
22
+ )
@@ -0,0 +1,22 @@
1
+ """
2
+ ZarPay Python SDK
3
+
4
+ Official SDK for integrating with the ZarPay payment gateway.
5
+
6
+ Usage:
7
+ from zarpay import ZarPay
8
+
9
+ client = ZarPay("sk_sandbox_xxxxxxxxxxxxx")
10
+
11
+ payment = client.payments.create(
12
+ merchant_order_id="ORD-123",
13
+ amount=1500,
14
+ channel_id=1,
15
+ customer_phone="03001234567",
16
+ )
17
+ """
18
+
19
+ from .client import ZarPay, ZarPayAPIError, verify_webhook
20
+
21
+ __version__ = "1.0.0"
22
+ __all__ = ["ZarPay", "ZarPayAPIError", "verify_webhook"]
@@ -0,0 +1,227 @@
1
+ """
2
+ ZarPay Python SDK — Client implementation
3
+ """
4
+
5
+ import hashlib
6
+ import hmac
7
+ import json
8
+ import time
9
+ from typing import Any, Dict, Optional
10
+ from urllib.parse import quote
11
+
12
+ import requests
13
+
14
+
15
+ DEFAULT_BASE_URL = "https://zarpay.pk/api/v1"
16
+ DEFAULT_TIMEOUT = 120
17
+
18
+
19
+ class ZarPayAPIError(Exception):
20
+ """Raised when the ZarPay API returns an error response."""
21
+
22
+ def __init__(self, status_code: int, error: str, body: dict):
23
+ self.status_code = status_code
24
+ self.error = error
25
+ self.body = body
26
+ super().__init__(f"ZarPay API error ({status_code}): {error}")
27
+
28
+
29
+ class PaymentsResource:
30
+ """Payment operations."""
31
+
32
+ def __init__(self, client: "ZarPay"):
33
+ self._client = client
34
+
35
+ def create(
36
+ self,
37
+ merchant_order_id: str,
38
+ amount: float,
39
+ channel_id: int,
40
+ customer_phone: str,
41
+ metadata: Optional[Dict[str, Any]] = None,
42
+ idempotency_key: Optional[str] = None,
43
+ ) -> dict:
44
+ """
45
+ Create a new payment.
46
+
47
+ Args:
48
+ merchant_order_id: Your unique order ID (max 100 chars)
49
+ amount: Amount in PKR (minimum 100)
50
+ channel_id: Channel ID from channels.list()
51
+ customer_phone: Customer phone (03XXXXXXXXX or +923XXXXXXXXX)
52
+ metadata: Optional custom key-value pairs
53
+ idempotency_key: Optional key to prevent duplicates
54
+
55
+ Returns:
56
+ Payment response dict with 'success' and 'data' keys
57
+
58
+ Raises:
59
+ ZarPayAPIError: If the API returns an error
60
+ """
61
+ body: Dict[str, Any] = {
62
+ "merchant_order_id": merchant_order_id,
63
+ "amount": amount,
64
+ "channel_id": channel_id,
65
+ "customer_phone": customer_phone,
66
+ }
67
+ if metadata is not None:
68
+ body["metadata"] = metadata
69
+ if idempotency_key is not None:
70
+ body["idempotency_key"] = idempotency_key
71
+
72
+ return self._client._request("POST", "/payments", json=body)
73
+
74
+ def get(self, zarpay_id: str) -> dict:
75
+ """
76
+ Get a payment by its ZarPay ID.
77
+
78
+ Args:
79
+ zarpay_id: The ZarPay-assigned payment ID (ZP_xxx)
80
+
81
+ Returns:
82
+ Payment response dict
83
+ """
84
+ return self._client._request("GET", f"/payments/{quote(zarpay_id, safe='')}")
85
+
86
+ def get_by_order_id(self, order_id: str) -> dict:
87
+ """
88
+ Get a payment by your merchant order ID.
89
+
90
+ Args:
91
+ order_id: Your merchant_order_id
92
+
93
+ Returns:
94
+ Payment response dict
95
+ """
96
+ return self._client._request(
97
+ "GET", f"/payments/by-order/{quote(order_id, safe='')}"
98
+ )
99
+
100
+
101
+ class ChannelsResource:
102
+ """Channel operations."""
103
+
104
+ def __init__(self, client: "ZarPay"):
105
+ self._client = client
106
+
107
+ def list(self) -> dict:
108
+ """
109
+ List available payment channels for your project.
110
+
111
+ Returns:
112
+ Channels response with payment_methods, channels, and mode
113
+ """
114
+ return self._client._request("GET", "/channels")
115
+
116
+
117
+ class ZarPay:
118
+ """
119
+ ZarPay API client.
120
+
121
+ Args:
122
+ api_key: Your ZarPay API key (sk_sandbox_... or sk_production_...)
123
+ base_url: API base URL (default: https://zarpay.pk/api/v1)
124
+ timeout: Request timeout in seconds (default: 120)
125
+
126
+ Example::
127
+
128
+ from zarpay import ZarPay
129
+
130
+ client = ZarPay("sk_sandbox_xxxxxxxxxxxxx")
131
+
132
+ # List channels
133
+ channels = client.channels.list()
134
+
135
+ # Create payment
136
+ payment = client.payments.create(
137
+ merchant_order_id="ORD-123",
138
+ amount=1500,
139
+ channel_id=1,
140
+ customer_phone="03001234567",
141
+ )
142
+ """
143
+
144
+ def __init__(
145
+ self,
146
+ api_key: str,
147
+ base_url: str = DEFAULT_BASE_URL,
148
+ timeout: int = DEFAULT_TIMEOUT,
149
+ ):
150
+ if not api_key:
151
+ raise ValueError("ZarPay API key is required")
152
+
153
+ self._api_key = api_key
154
+ self._base_url = base_url.rstrip("/")
155
+ self._timeout = timeout
156
+ self._session = requests.Session()
157
+ self._session.headers.update(
158
+ {
159
+ "Authorization": f"Bearer {api_key}",
160
+ "Content-Type": "application/json",
161
+ "User-Agent": "zarpay-python/1.0.0",
162
+ }
163
+ )
164
+
165
+ self.payments = PaymentsResource(self)
166
+ self.channels = ChannelsResource(self)
167
+
168
+ def _request(self, method: str, path: str, **kwargs) -> dict:
169
+ url = f"{self._base_url}{path}"
170
+ response = self._session.request(
171
+ method, url, timeout=self._timeout, **kwargs
172
+ )
173
+ data = response.json()
174
+
175
+ if not response.ok and "error" in data:
176
+ raise ZarPayAPIError(response.status_code, data["error"], data)
177
+
178
+ return data
179
+
180
+
181
+ def verify_webhook(
182
+ raw_body: bytes,
183
+ signature_header: str,
184
+ secret: str,
185
+ tolerance_sec: int = 300,
186
+ ) -> dict:
187
+ """
188
+ Verify a ZarPay webhook signature.
189
+
190
+ Args:
191
+ raw_body: The raw request body (bytes)
192
+ signature_header: The X-ZarPay-Signature header value
193
+ secret: Your webhook signing secret (whsec_...)
194
+ tolerance_sec: Max age in seconds (default: 300)
195
+
196
+ Returns:
197
+ The parsed webhook payload dict
198
+
199
+ Raises:
200
+ ValueError: If signature is invalid or timestamp is too old
201
+ """
202
+ parts = {}
203
+ for part in signature_header.split(","):
204
+ key, _, value = part.partition("=")
205
+ parts[key] = value
206
+
207
+ t = parts.get("t", "")
208
+ v1 = parts.get("v1", "")
209
+
210
+ if not t or not v1:
211
+ raise ValueError("Invalid X-ZarPay-Signature header format")
212
+
213
+ timestamp = int(t)
214
+ if abs(time.time() - timestamp) > tolerance_sec:
215
+ raise ValueError("Webhook timestamp too old — possible replay attack")
216
+
217
+ body_str = raw_body.decode("utf-8") if isinstance(raw_body, bytes) else raw_body
218
+ expected = hmac.new(
219
+ secret.encode("utf-8"),
220
+ f"{t}.{body_str}".encode("utf-8"),
221
+ digestmod=hashlib.sha256,
222
+ ).hexdigest()
223
+
224
+ if not hmac.compare_digest(expected, v1):
225
+ raise ValueError("Invalid webhook signature")
226
+
227
+ return json.loads(raw_body)
@@ -0,0 +1,146 @@
1
+ Metadata-Version: 2.4
2
+ Name: zarpay
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for the ZarPay payment gateway
5
+ Home-page: https://github.com/zarpay/zarpay-python
6
+ Author: ZarPay
7
+ Author-email: support@zarpay.pk
8
+ License: MIT
9
+ Keywords: zarpay,payments,jazzcash,easypaisa,pakistan
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: >=3.8
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: requests>=2.20.0
17
+ Dynamic: author
18
+ Dynamic: author-email
19
+ Dynamic: classifier
20
+ Dynamic: description
21
+ Dynamic: description-content-type
22
+ Dynamic: home-page
23
+ Dynamic: keywords
24
+ Dynamic: license
25
+ Dynamic: license-file
26
+ Dynamic: requires-dist
27
+ Dynamic: requires-python
28
+ Dynamic: summary
29
+
30
+ # ZarPay Python SDK
31
+
32
+ Official Python SDK for the [ZarPay](https://zarpay.pk) payment gateway.
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ pip install zarpay
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ```python
43
+ from zarpay import ZarPay
44
+
45
+ client = ZarPay("sk_sandbox_xxxxxxxxxxxxx")
46
+
47
+ payment = client.payments.create(
48
+ merchant_order_id="ORD-123",
49
+ amount=1500,
50
+ channel_id=1,
51
+ customer_phone="03001234567",
52
+ )
53
+
54
+ print(payment["data"]["status"]) # 'completed' | 'processing' | 'failed'
55
+ ```
56
+
57
+ ## Usage
58
+
59
+ ### List Available Channels
60
+
61
+ ```python
62
+ channels = client.channels.list()
63
+
64
+ for ch in channels["data"]["channels"]:
65
+ print(f"{ch['id']}: {ch['wallet_type']}")
66
+ ```
67
+
68
+ ### Create a Payment
69
+
70
+ ```python
71
+ payment = client.payments.create(
72
+ merchant_order_id="ORD-456",
73
+ amount=2500,
74
+ channel_id=1,
75
+ customer_phone="03001234567",
76
+ metadata={"customer_name": "Ahmed Khan"},
77
+ idempotency_key="unique-key-456",
78
+ )
79
+
80
+ if payment["success"]:
81
+ print("Payment completed:", payment["data"]["zarpay_id"])
82
+ else:
83
+ print("Payment failed:", payment["data"]["failure_reason"])
84
+ ```
85
+
86
+ ### Get Payment Status
87
+
88
+ ```python
89
+ # By ZarPay ID
90
+ payment = client.payments.get("ZP_abc123def456")
91
+
92
+ # By your order ID
93
+ payment = client.payments.get_by_order_id("ORD-456")
94
+ ```
95
+
96
+ ### Verify Webhooks
97
+
98
+ ```python
99
+ from zarpay import verify_webhook
100
+
101
+ # In your webhook handler (e.g. Flask/Django)
102
+ def webhook_handler(request):
103
+ try:
104
+ event = verify_webhook(
105
+ raw_body=request.body,
106
+ signature_header=request.headers["X-ZarPay-Signature"],
107
+ secret="whsec_your_webhook_secret",
108
+ )
109
+
110
+ if event["event"] == "payment.completed":
111
+ # Fulfill the order
112
+ pass
113
+ elif event["event"] == "payment.failed":
114
+ # Notify customer
115
+ pass
116
+
117
+ return HttpResponse(status=200)
118
+ except ValueError:
119
+ return HttpResponse(status=400)
120
+ ```
121
+
122
+ ### Error Handling
123
+
124
+ ```python
125
+ from zarpay import ZarPay, ZarPayAPIError
126
+
127
+ try:
128
+ payment = client.payments.create(...)
129
+ except ZarPayAPIError as e:
130
+ print(e.status_code) # 400, 401, 409, etc.
131
+ print(e.error) # Human-readable error message
132
+ ```
133
+
134
+ ### Configuration
135
+
136
+ ```python
137
+ client = ZarPay(
138
+ "sk_sandbox_xxx",
139
+ base_url="http://localhost:3000/api/v1", # local development
140
+ timeout=60, # seconds
141
+ )
142
+ ```
143
+
144
+ ## License
145
+
146
+ MIT
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ zarpay/__init__.py
6
+ zarpay/client.py
7
+ zarpay.egg-info/PKG-INFO
8
+ zarpay.egg-info/SOURCES.txt
9
+ zarpay.egg-info/dependency_links.txt
10
+ zarpay.egg-info/requires.txt
11
+ zarpay.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ requests>=2.20.0
@@ -0,0 +1 @@
1
+ zarpay