zayono 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.
@@ -0,0 +1,20 @@
1
+ /dist
2
+ /build
3
+ /__pycache__
4
+ **/__pycache__
5
+ *.egg-info
6
+ *.egg
7
+ .venv
8
+ venv
9
+ .env
10
+ .pytest_cache
11
+ .mypy_cache
12
+ .tox
13
+ .coverage
14
+ htmlcov/
15
+ *.pyc
16
+ *.pyo
17
+ *.pyd
18
+ .DS_Store
19
+ .idea/
20
+ .vscode/
zayono-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zayono
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.
zayono-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,267 @@
1
+ Metadata-Version: 2.4
2
+ Name: zayono
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for the Zayono unified Mobile Money payment gateway.
5
+ Project-URL: Homepage, https://zayono.com
6
+ Project-URL: Documentation, https://docs.zayono.com/sdks/python
7
+ Project-URL: Repository, https://github.com/RomualdAKM/sdks-zayono/tree/main/zayono-python
8
+ Project-URL: Issues, https://github.com/RomualdAKM/sdks-zayono/issues
9
+ Author-email: Zayono <developers@zayono.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: africa,asyncio,httpx,mobile-money,payment-gateway,payments,sdk,zayono
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Framework :: AsyncIO
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3 :: Only
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Programming Language :: Python :: 3.13
26
+ Classifier: Topic :: Office/Business :: Financial
27
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
28
+ Classifier: Typing :: Typed
29
+ Requires-Python: >=3.9
30
+ Requires-Dist: httpx<1,>=0.25
31
+ Provides-Extra: dev
32
+ Requires-Dist: build>=1.0; extra == 'dev'
33
+ Requires-Dist: mypy>=1.7; extra == 'dev'
34
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
35
+ Requires-Dist: pytest>=7.4; extra == 'dev'
36
+ Requires-Dist: respx>=0.20; extra == 'dev'
37
+ Provides-Extra: test
38
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'test'
39
+ Requires-Dist: pytest>=7.4; extra == 'test'
40
+ Requires-Dist: respx>=0.20; extra == 'test'
41
+ Description-Content-Type: text/markdown
42
+
43
+ # Zayono Python SDK
44
+
45
+ [![PyPI version](https://img.shields.io/pypi/v/zayono.svg)](https://pypi.org/project/zayono/)
46
+ [![Python versions](https://img.shields.io/pypi/pyversions/zayono.svg)](https://pypi.org/project/zayono/)
47
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/RomualdAKM/sdks-zayono/blob/main/zayono-python/LICENSE)
48
+
49
+ Official Python SDK for the [Zayono](https://zayono.com) unified Mobile Money
50
+ payment gateway for Africa.
51
+
52
+ - **Sync + async** out of the box: `Zayono` and `AsyncZayono`.
53
+ - **Type-safe**: ships `py.typed`; complete type hints picked up by mypy/pyright/Pylance.
54
+ - **Resilient**: automatic retries (429/5xx/connect) with jittered exponential backoff,
55
+ honours `Retry-After`.
56
+ - **Idempotent by default**: every mutating request carries an auto-generated
57
+ `X-Idempotency-Key` (UUIDv4); override with `idempotency_key=`.
58
+ - **Framework-agnostic**: integrates with Django, Flask, FastAPI, Starlette, etc.
59
+
60
+ ## Installation
61
+
62
+ ```bash
63
+ pip install zayono
64
+ ```
65
+
66
+ Requires Python 3.9+.
67
+
68
+ ## Quick start (sync)
69
+
70
+ ```python
71
+ import os
72
+ from zayono import Zayono
73
+
74
+ client = Zayono(api_key=os.environ["ZAYONO_API_KEY"])
75
+
76
+ payment = client.payments.create(
77
+ amount=5000,
78
+ currency="XOF",
79
+ description="Premium t-shirt",
80
+ customer={
81
+ "email": "customer@example.com",
82
+ "first_name": "Jean",
83
+ "last_name": "Dupont",
84
+ },
85
+ return_url="https://example.com/success",
86
+ metadata={"order_id": "ORD-12345"},
87
+ )
88
+
89
+ print(payment["checkout_url"])
90
+ ```
91
+
92
+ ## Quick start (async)
93
+
94
+ ```python
95
+ import asyncio
96
+ from zayono import AsyncZayono
97
+
98
+ async def main():
99
+ async with AsyncZayono(api_key="zyn_test_xxxxx") as client:
100
+ payment = await client.payments.create(
101
+ amount=5000,
102
+ currency="XOF",
103
+ description="Premium t-shirt",
104
+ return_url="https://example.com/success",
105
+ customer={
106
+ "email": "c@example.com",
107
+ "first_name": "Jean",
108
+ "last_name": "Dupont",
109
+ },
110
+ )
111
+ print(payment["checkout_url"])
112
+
113
+ asyncio.run(main())
114
+ ```
115
+
116
+ ## Examples
117
+
118
+ ### 1. Initiate a payment with a specific operator (no hosted page)
119
+
120
+ ```python
121
+ from zayono import Zayono
122
+
123
+ client = Zayono(api_key="zyn_test_xxxxx")
124
+
125
+ payment = client.payments.create(
126
+ amount=15000,
127
+ currency="XOF",
128
+ operator="mtn_bj",
129
+ description="Plan Pro mensuel",
130
+ return_url="https://example.com/success",
131
+ customer={
132
+ "email": "c@example.com",
133
+ "first_name": "Jean",
134
+ "last_name": "Dupont",
135
+ "phone": "+22961000000",
136
+ },
137
+ )
138
+ # Payment is dispatched immediately. Poll its status via retrieve()
139
+ ```
140
+
141
+ ### 2. Initiate a payout (disbursement), async
142
+
143
+ ```python
144
+ import asyncio
145
+ from zayono import AsyncZayono
146
+
147
+ async def disburse():
148
+ async with AsyncZayono(api_key="zyn_test_xxxxx") as client:
149
+ payout = await client.payouts.create(
150
+ amount=20000,
151
+ currency="XOF",
152
+ operator="moov_bj",
153
+ recipient={
154
+ "phone": "+22961000000",
155
+ "first_name": "Kossi",
156
+ "last_name": "Mensah",
157
+ },
158
+ description="Payout for order ORD-12345",
159
+ )
160
+ print(payout["id"], payout["status"])
161
+
162
+ asyncio.run(disburse())
163
+ ```
164
+
165
+ ### 3. Stream every successful payment (auto-paginated)
166
+
167
+ ```python
168
+ from zayono import Zayono
169
+
170
+ client = Zayono(api_key="zyn_test_xxxxx")
171
+
172
+ for payment in client.payments.list(status="success", per_page=100):
173
+ print(payment["id"], payment["amount"], payment["currency"])
174
+ ```
175
+
176
+ Async equivalent:
177
+
178
+ ```python
179
+ async for payment in async_client.payments.list(status="success"):
180
+ print(payment["id"])
181
+ ```
182
+
183
+ ### 4. Verify a webhook signature (FastAPI)
184
+
185
+ ```python
186
+ from fastapi import FastAPI, Request, HTTPException
187
+ from zayono import Zayono
188
+ import os
189
+
190
+ app = FastAPI()
191
+ client = Zayono(api_key=os.environ["ZAYONO_API_KEY"])
192
+
193
+ @app.post("/webhooks/zayono")
194
+ async def webhook(request: Request):
195
+ body = await request.body() # raw bytes, required
196
+ signature = request.headers.get("x-zayono-signature", "")
197
+ secret = os.environ["ZAYONO_WEBHOOK_SECRET"]
198
+
199
+ if not client.webhooks.verify(body, signature, secret):
200
+ raise HTTPException(401, "Invalid signature")
201
+
202
+ event = await request.json()
203
+ # ... handle event["type"], event["data"]
204
+ return {"received": True}
205
+ ```
206
+
207
+ > **Refunds**: the public API-key surface does not yet expose
208
+ > `POST /v1/payments/{id}/refunds`. For now, trigger refunds from the
209
+ > Zayono merchant dashboard. A `refunds` resource will be added to this
210
+ > SDK once the endpoint ships on the v1 surface.
211
+
212
+ ## Error handling
213
+
214
+ ```python
215
+ from zayono.exceptions import (
216
+ ValidationError, AuthenticationError, RateLimitError,
217
+ NotFoundError, ServerError, NetworkError,
218
+ )
219
+
220
+ try:
221
+ payment = client.payments.create(amount=-1, currency="XOF")
222
+ except ValidationError as e:
223
+ # 422: e.errors is dict[str, list[str]]
224
+ for field, messages in e.errors.items():
225
+ print(f"{field}: {', '.join(messages)}")
226
+ except AuthenticationError:
227
+ # 401 / 403
228
+ ...
229
+ except RateLimitError as e:
230
+ # 429: e.retry_after is in seconds, may be None
231
+ ...
232
+ except NotFoundError:
233
+ # 404
234
+ ...
235
+ except ServerError:
236
+ # 5xx after retries exhausted
237
+ ...
238
+ except NetworkError:
239
+ # Transport-level failure (timeout, connect refused, DNS)
240
+ ...
241
+ ```
242
+
243
+ ## Configuration
244
+
245
+ ```python
246
+ client = Zayono(
247
+ api_key="zyn_test_xxxxx",
248
+ base_url="https://backend.zayono.com/api/v1", # default
249
+ timeout=30.0, # seconds, default 30
250
+ max_retries=3, # default 3
251
+ application_id=None, # only needed for dashboard endpoints
252
+ )
253
+ ```
254
+
255
+ ## Development
256
+
257
+ ```bash
258
+ git clone https://github.com/RomualdAKM/sdks-zayono
259
+ cd sdks-zayono/zayono-python
260
+ pip install -e ".[test]"
261
+ pytest # run the test suite
262
+ python -m build # produce wheel + sdist into dist/
263
+ ```
264
+
265
+ ## License
266
+
267
+ MIT. See [LICENSE](https://github.com/RomualdAKM/sdks-zayono/blob/main/zayono-python/LICENSE).
zayono-1.0.0/README.md ADDED
@@ -0,0 +1,225 @@
1
+ # Zayono Python SDK
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/zayono.svg)](https://pypi.org/project/zayono/)
4
+ [![Python versions](https://img.shields.io/pypi/pyversions/zayono.svg)](https://pypi.org/project/zayono/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/RomualdAKM/sdks-zayono/blob/main/zayono-python/LICENSE)
6
+
7
+ Official Python SDK for the [Zayono](https://zayono.com) unified Mobile Money
8
+ payment gateway for Africa.
9
+
10
+ - **Sync + async** out of the box: `Zayono` and `AsyncZayono`.
11
+ - **Type-safe**: ships `py.typed`; complete type hints picked up by mypy/pyright/Pylance.
12
+ - **Resilient**: automatic retries (429/5xx/connect) with jittered exponential backoff,
13
+ honours `Retry-After`.
14
+ - **Idempotent by default**: every mutating request carries an auto-generated
15
+ `X-Idempotency-Key` (UUIDv4); override with `idempotency_key=`.
16
+ - **Framework-agnostic**: integrates with Django, Flask, FastAPI, Starlette, etc.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install zayono
22
+ ```
23
+
24
+ Requires Python 3.9+.
25
+
26
+ ## Quick start (sync)
27
+
28
+ ```python
29
+ import os
30
+ from zayono import Zayono
31
+
32
+ client = Zayono(api_key=os.environ["ZAYONO_API_KEY"])
33
+
34
+ payment = client.payments.create(
35
+ amount=5000,
36
+ currency="XOF",
37
+ description="Premium t-shirt",
38
+ customer={
39
+ "email": "customer@example.com",
40
+ "first_name": "Jean",
41
+ "last_name": "Dupont",
42
+ },
43
+ return_url="https://example.com/success",
44
+ metadata={"order_id": "ORD-12345"},
45
+ )
46
+
47
+ print(payment["checkout_url"])
48
+ ```
49
+
50
+ ## Quick start (async)
51
+
52
+ ```python
53
+ import asyncio
54
+ from zayono import AsyncZayono
55
+
56
+ async def main():
57
+ async with AsyncZayono(api_key="zyn_test_xxxxx") as client:
58
+ payment = await client.payments.create(
59
+ amount=5000,
60
+ currency="XOF",
61
+ description="Premium t-shirt",
62
+ return_url="https://example.com/success",
63
+ customer={
64
+ "email": "c@example.com",
65
+ "first_name": "Jean",
66
+ "last_name": "Dupont",
67
+ },
68
+ )
69
+ print(payment["checkout_url"])
70
+
71
+ asyncio.run(main())
72
+ ```
73
+
74
+ ## Examples
75
+
76
+ ### 1. Initiate a payment with a specific operator (no hosted page)
77
+
78
+ ```python
79
+ from zayono import Zayono
80
+
81
+ client = Zayono(api_key="zyn_test_xxxxx")
82
+
83
+ payment = client.payments.create(
84
+ amount=15000,
85
+ currency="XOF",
86
+ operator="mtn_bj",
87
+ description="Plan Pro mensuel",
88
+ return_url="https://example.com/success",
89
+ customer={
90
+ "email": "c@example.com",
91
+ "first_name": "Jean",
92
+ "last_name": "Dupont",
93
+ "phone": "+22961000000",
94
+ },
95
+ )
96
+ # Payment is dispatched immediately. Poll its status via retrieve()
97
+ ```
98
+
99
+ ### 2. Initiate a payout (disbursement), async
100
+
101
+ ```python
102
+ import asyncio
103
+ from zayono import AsyncZayono
104
+
105
+ async def disburse():
106
+ async with AsyncZayono(api_key="zyn_test_xxxxx") as client:
107
+ payout = await client.payouts.create(
108
+ amount=20000,
109
+ currency="XOF",
110
+ operator="moov_bj",
111
+ recipient={
112
+ "phone": "+22961000000",
113
+ "first_name": "Kossi",
114
+ "last_name": "Mensah",
115
+ },
116
+ description="Payout for order ORD-12345",
117
+ )
118
+ print(payout["id"], payout["status"])
119
+
120
+ asyncio.run(disburse())
121
+ ```
122
+
123
+ ### 3. Stream every successful payment (auto-paginated)
124
+
125
+ ```python
126
+ from zayono import Zayono
127
+
128
+ client = Zayono(api_key="zyn_test_xxxxx")
129
+
130
+ for payment in client.payments.list(status="success", per_page=100):
131
+ print(payment["id"], payment["amount"], payment["currency"])
132
+ ```
133
+
134
+ Async equivalent:
135
+
136
+ ```python
137
+ async for payment in async_client.payments.list(status="success"):
138
+ print(payment["id"])
139
+ ```
140
+
141
+ ### 4. Verify a webhook signature (FastAPI)
142
+
143
+ ```python
144
+ from fastapi import FastAPI, Request, HTTPException
145
+ from zayono import Zayono
146
+ import os
147
+
148
+ app = FastAPI()
149
+ client = Zayono(api_key=os.environ["ZAYONO_API_KEY"])
150
+
151
+ @app.post("/webhooks/zayono")
152
+ async def webhook(request: Request):
153
+ body = await request.body() # raw bytes, required
154
+ signature = request.headers.get("x-zayono-signature", "")
155
+ secret = os.environ["ZAYONO_WEBHOOK_SECRET"]
156
+
157
+ if not client.webhooks.verify(body, signature, secret):
158
+ raise HTTPException(401, "Invalid signature")
159
+
160
+ event = await request.json()
161
+ # ... handle event["type"], event["data"]
162
+ return {"received": True}
163
+ ```
164
+
165
+ > **Refunds**: the public API-key surface does not yet expose
166
+ > `POST /v1/payments/{id}/refunds`. For now, trigger refunds from the
167
+ > Zayono merchant dashboard. A `refunds` resource will be added to this
168
+ > SDK once the endpoint ships on the v1 surface.
169
+
170
+ ## Error handling
171
+
172
+ ```python
173
+ from zayono.exceptions import (
174
+ ValidationError, AuthenticationError, RateLimitError,
175
+ NotFoundError, ServerError, NetworkError,
176
+ )
177
+
178
+ try:
179
+ payment = client.payments.create(amount=-1, currency="XOF")
180
+ except ValidationError as e:
181
+ # 422: e.errors is dict[str, list[str]]
182
+ for field, messages in e.errors.items():
183
+ print(f"{field}: {', '.join(messages)}")
184
+ except AuthenticationError:
185
+ # 401 / 403
186
+ ...
187
+ except RateLimitError as e:
188
+ # 429: e.retry_after is in seconds, may be None
189
+ ...
190
+ except NotFoundError:
191
+ # 404
192
+ ...
193
+ except ServerError:
194
+ # 5xx after retries exhausted
195
+ ...
196
+ except NetworkError:
197
+ # Transport-level failure (timeout, connect refused, DNS)
198
+ ...
199
+ ```
200
+
201
+ ## Configuration
202
+
203
+ ```python
204
+ client = Zayono(
205
+ api_key="zyn_test_xxxxx",
206
+ base_url="https://backend.zayono.com/api/v1", # default
207
+ timeout=30.0, # seconds, default 30
208
+ max_retries=3, # default 3
209
+ application_id=None, # only needed for dashboard endpoints
210
+ )
211
+ ```
212
+
213
+ ## Development
214
+
215
+ ```bash
216
+ git clone https://github.com/RomualdAKM/sdks-zayono
217
+ cd sdks-zayono/zayono-python
218
+ pip install -e ".[test]"
219
+ pytest # run the test suite
220
+ python -m build # produce wheel + sdist into dist/
221
+ ```
222
+
223
+ ## License
224
+
225
+ MIT. See [LICENSE](https://github.com/RomualdAKM/sdks-zayono/blob/main/zayono-python/LICENSE).
@@ -0,0 +1,39 @@
1
+ # `checkout` resource
2
+
3
+ `POST /v1/checkout/initialize`.
4
+
5
+ ## `checkout.initialize(...)`
6
+
7
+ Create a hosted-checkout session and receive a `checkout_url` to redirect
8
+ the customer to. The session collects the operator + phone on the merchant's
9
+ behalf, the SDK is a thin pass-through.
10
+
11
+ ```python
12
+ session = client.checkout.initialize(
13
+ amount=12500,
14
+ currency="XOF",
15
+ description="Premium subscription",
16
+ customer_email="c@example.com",
17
+ return_url="https://example.com/thanks",
18
+ cancel_url="https://example.com/cart",
19
+ metadata={"order_id": "ORD-789"},
20
+ )
21
+
22
+ # Redirect the customer:
23
+ print(session["checkout_url"])
24
+ ```
25
+
26
+ | Parameter | Type | Required | Notes |
27
+ |-------------------|--------------------------|----------|------------------------------------|
28
+ | `amount` | `int` | yes | Minor units. |
29
+ | `currency` | `str` | yes | ISO-4217. |
30
+ | `description` | `str \| None` | no | |
31
+ | `customer_email` | `str \| None` | no | |
32
+ | `customer_name` | `str \| None` | no | |
33
+ | `customer_id` | `str \| None` | no | |
34
+ | `return_url` | `str \| None` | no | |
35
+ | `cancel_url` | `str \| None` | no | |
36
+ | `callback_url` | `str \| None` | no | |
37
+ | `metadata` | `dict[str, Any] \| None` | no | |
38
+ | `idempotency_key` | `str \| None` | no | |
39
+ | `extra` | `dict[str, Any] \| None` | no | Forward-compatible escape hatch. |
@@ -0,0 +1,27 @@
1
+ # `customers` resource
2
+
3
+ `GET /v1/customers/{id}`, `GET /v1/customers`.
4
+
5
+ Customer rows are created implicitly when you initiate a payment with a new
6
+ `customer_email`. The endpoints are read-only, there is no
7
+ `customers.create(...)`.
8
+
9
+ ## `customers.retrieve(customer_id)`
10
+
11
+ ```python
12
+ customer = client.customers.retrieve("019e5eaf-cb99-7351-a6d5-c219e28534db")
13
+ print(customer["email"], customer["total_payments"])
14
+ ```
15
+
16
+ ## `customers.list(...)` / `async for customer in ...`
17
+
18
+ Paginator over every customer. Filters:
19
+
20
+ - `email`, `phone`, `country`
21
+ - `search` (substring match against `email`, `name`, `phone`)
22
+ - `per_page` (default 20)
23
+
24
+ ```python
25
+ for c in client.customers.list(country="BJ"):
26
+ print(c["id"], c["email"])
27
+ ```
@@ -0,0 +1,65 @@
1
+ # `payments` resource
2
+
3
+ `POST /v1/payments/initialize`, `GET /v1/payments/{id}`, `GET /v1/payments`.
4
+
5
+ ## `payments.create(...)` / `await async_client.payments.create(...)`
6
+
7
+ Initialise a payment. Returns the created payment resource as a dict
8
+ (the `data` field of the API envelope).
9
+
10
+ | Parameter | Type | Required | Notes |
11
+ |-------------------|---------------------------------|----------|----------------------------------------------------------------------------------------|
12
+ | `amount` | `int` | yes | Amount in **minor units** of `currency` (e.g. 500 = 5.00 XOF for an integer currency). |
13
+ | `currency` | `str` | yes | ISO-4217 code: `XOF`, `XAF`, `NGN`, `GHS`, `KES`, etc. |
14
+ | `description` | `str \| None` | no | Free-form merchant-side description. |
15
+ | `customer_email` | `str \| None` | no | Required by some aggregators for receipts. |
16
+ | `customer_name` | `str \| None` | no | |
17
+ | `customer_id` | `str \| None` | no | Pre-existing Zayono customer UUID, links the payment to that record. |
18
+ | `phone` | `str \| None` | no | E.164 (`+22961000000`). Mandatory when `operator` is set. |
19
+ | `operator` | `str \| None` | no | If set, dispatches immediately (`mtn_bj`, `moov_bj`, `orange_ci`, …). |
20
+ | `return_url` | `str \| None` | no | Where to redirect after success on the hosted page. |
21
+ | `cancel_url` | `str \| None` | no | Where to redirect after cancel. |
22
+ | `callback_url` | `str \| None` | no | Per-payment webhook override. |
23
+ | `metadata` | `dict[str, Any] \| None` | no | Echoed back on webhooks and `retrieve()`. |
24
+ | `idempotency_key` | `str \| None` | no | Override the auto-generated UUIDv4. |
25
+ | `extra` | `dict[str, Any] \| None` | no | Escape hatch for forward-compatible fields. |
26
+
27
+ ```python
28
+ payment = client.payments.create(
29
+ amount=5000,
30
+ currency="XOF",
31
+ customer_email="c@example.com",
32
+ return_url="https://example.com/success",
33
+ metadata={"order_id": "ORD-12345"},
34
+ )
35
+ ```
36
+
37
+ ## `payments.retrieve(payment_id)` / `await ...`
38
+
39
+ Fetch a payment by id.
40
+
41
+ ```python
42
+ payment = client.payments.retrieve("019e5eaf-cb99-7351-a6d5-c219e28534db")
43
+ if payment["status"] == "success":
44
+ ...
45
+ ```
46
+
47
+ ## `payments.list(...)` / `async for ... in async_client.payments.list(...)`
48
+
49
+ Returns a paginator (sync or async). Pagination is fully transparent, the
50
+ SDK fetches the next page lazily until the result set is exhausted.
51
+
52
+ Filters:
53
+
54
+ - `status`: `"pending" | "processing" | "success" | "failed" | "cancelled" | "expired" | "refunded" | "partially_refunded"`
55
+ - `customer_id`, `operator`, `currency`
56
+ - `from_date`, `to_date` (ISO-8601)
57
+ - `per_page` (1–100, default 20)
58
+
59
+ ```python
60
+ for payment in client.payments.list(status="success", per_page=50):
61
+ ...
62
+ ```
63
+
64
+ For a single page with pagination metadata, use `list_page(...)` and inspect
65
+ the returned envelope.