arionpay 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.
arionpay-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ArionPay
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.
@@ -0,0 +1,201 @@
1
+ Metadata-Version: 2.4
2
+ Name: arionpay
3
+ Version: 1.0.0
4
+ Summary: Official Python client for ArionPay: create crypto invoices and verify webhooks. Payments go straight to your own wallet.
5
+ Author-email: ArionPay <info@arionpay.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://arionpay.com
8
+ Project-URL: Documentation, https://arionpay.com/knowledge-base
9
+ Project-URL: Source, https://github.com/ArionPay-Dev/arionpay-python
10
+ Project-URL: Changelog, https://github.com/ArionPay-Dev/arionpay-python/blob/main/CHANGELOG.md
11
+ Keywords: arionpay,crypto,payments,bitcoin,usdt,payment-gateway,webhook
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Topic :: Office/Business :: Financial
15
+ Classifier: Typing :: Typed
16
+ Requires-Python: >=3.8
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Dynamic: license-file
20
+
21
+ # ArionPay for Python
22
+
23
+ Official Python client for [ArionPay](https://arionpay.com). Create crypto invoices, send customers to the payment page, and check webhooks. The money goes straight to your own wallet: ArionPay never holds it.
24
+
25
+ - No dependencies (standard library only). Python 3.8 or newer.
26
+ - Works with Flask, Django, FastAPI or plain scripts.
27
+ - Safe retries: every invoice request carries an idempotency key, so a network error can never create two invoices.
28
+
29
+ ```bash
30
+ pip install arionpay
31
+ ```
32
+
33
+ ## Keys
34
+
35
+ In your ArionPay dashboard, open your store:
36
+
37
+ | Value | Where | Starts with |
38
+ | --- | --- | --- |
39
+ | API key | Store page, **API key** | `pk_` |
40
+ | API secret | Store page, **API secret** (asks for your authenticator code) | `sk_` |
41
+ | Webhook secret | **Webhooks** page, **signing secret** | `whsec_` |
42
+
43
+ Keep them on your server, for example in environment variables.
44
+
45
+ ## Take a payment
46
+
47
+ ```python
48
+ import os
49
+ from arionpay import ArionPay
50
+
51
+ arionpay = ArionPay(
52
+ api_key=os.environ["ARIONPAY_API_KEY"],
53
+ api_secret=os.environ["ARIONPAY_API_SECRET"],
54
+ webhook_secret=os.environ["ARIONPAY_WEBHOOK_SECRET"],
55
+ )
56
+
57
+ invoice = arionpay.create_invoice(
58
+ amount="49.90",
59
+ currency="USD",
60
+ order_id="1001",
61
+ success_url="https://shop.example.com/thanks/1001",
62
+ cancel_url="https://shop.example.com/cart",
63
+ metadata={"user_id": 42},
64
+ )
65
+ # send the customer to invoice["invoiceUrl"]
66
+ ```
67
+
68
+ The customer coming back to `success_url` does **not** prove they paid. Deliver the order when the `invoice.paid` webhook arrives (or when `get_invoice` says `paid`).
69
+
70
+ Invoices are returned as dicts with the same field names as the webhook's `data.invoice` (`id`, `status`, `orderId`, `amountFiat`, `currency`, `asset`, `paidCrypto`, `transactions`, `test`, `metadata`, ...), so one function can handle a webhook and a read.
71
+
72
+ ## Webhooks
73
+
74
+ Set your webhook address on the **Webhooks** page of the dashboard (a public `https://` address), or per invoice with `callback_url`. Check the signature against the **raw** body, before you parse it.
75
+
76
+ ### Flask
77
+
78
+ ```python
79
+ from flask import Flask, request
80
+ from arionpay import SignatureError, is_test_event
81
+
82
+ app = Flask(__name__)
83
+
84
+ @app.post("/arionpay/webhook")
85
+ def arionpay_webhook():
86
+ try:
87
+ event = arionpay.verify_webhook(request.get_data(), request.headers.get("ArionPay-Signature"))
88
+ except SignatureError:
89
+ return {"error": "invalid_signature"}, 401
90
+ if is_test_event(event):
91
+ return {"received": True} # "Send test webhook": not a real order
92
+ handle_event(event)
93
+ return {"received": True}
94
+ ```
95
+
96
+ ### Django
97
+
98
+ ```python
99
+ from django.http import JsonResponse
100
+ from django.views.decorators.csrf import csrf_exempt
101
+ from django.views.decorators.http import require_POST
102
+ from arionpay import SignatureError, is_test_event
103
+
104
+ @csrf_exempt
105
+ @require_POST
106
+ def arionpay_webhook(request):
107
+ try:
108
+ event = arionpay.verify_webhook(request.body, request.headers.get("ArionPay-Signature"))
109
+ except SignatureError:
110
+ return JsonResponse({"error": "invalid_signature"}, status=401)
111
+ if not is_test_event(event):
112
+ handle_event(event)
113
+ return JsonResponse({"received": True})
114
+ ```
115
+
116
+ ### FastAPI
117
+
118
+ ```python
119
+ from fastapi import FastAPI, Request, Response
120
+ from arionpay import SignatureError, is_test_event
121
+
122
+ app = FastAPI()
123
+
124
+ @app.post("/arionpay/webhook")
125
+ async def arionpay_webhook(request: Request):
126
+ raw = await request.body()
127
+ try:
128
+ event = arionpay.verify_webhook(raw, request.headers.get("arionpay-signature"))
129
+ except SignatureError:
130
+ return Response(status_code=401)
131
+ if not is_test_event(event):
132
+ handle_event(event)
133
+ return {"received": True}
134
+ ```
135
+
136
+ ### Handling an event
137
+
138
+ ```python
139
+ def handle_event(event):
140
+ if already_processed(event["id"]): # the same event can arrive more than once
141
+ return
142
+ invoice = event["data"]["invoice"]
143
+ order = find_order(invoice["orderId"])
144
+ if event["type"] == "invoice.paid" and order and not order.paid:
145
+ same_total = f"{float(order.total):.2f}" == f"{float(invoice['amountFiat']):.2f}"
146
+ if same_total and order.currency == invoice["currency"] and invoice["test"] == order.is_test:
147
+ mark_order_paid(order, invoice) # deliver here
148
+ remember_processed(event["id"])
149
+ ```
150
+
151
+ | Event | Meaning | What to do |
152
+ | --- | --- | --- |
153
+ | `invoice.pending` | A payment was seen on the network and waits for confirmations. | Show "payment on its way". Do not deliver yet. |
154
+ | `invoice.partial` | Less than the full amount arrived. The invoice stays open for the rest. | Do not deliver. |
155
+ | `invoice.paid` | Fully paid and confirmed. Also sent when you accept a payment by hand in the dashboard. | Deliver the order. |
156
+ | `invoice.expired` | Time ran out without full payment. A late payment can still make it `paid`. | Keep the order unpaid. |
157
+ | `invoice.needs_review` | Something needs a person, for example more money arrived after the invoice was paid. | Tell a human. Do not change the order. |
158
+
159
+ ArionPay sends again when your server does not answer `2xx` (for about 3 days).
160
+
161
+ ### Rules for a safe integration
162
+
163
+ 1. Check the signature on the raw body. Never trust a webhook you could not verify.
164
+ 2. Deliver only on `invoice.paid` (or `get_invoice(...)["status"] == "paid"`).
165
+ 3. Match the invoice to your order: your `order_id` or `metadata`, and the same amount and currency as the order's current total.
166
+ 4. Ignore test events (`is_test_event(event)`), and in your live shop ignore invoices with `"test": True`.
167
+ 5. Handle each `event["id"]` once, and answer `2xx` quickly.
168
+ 6. Do not compare crypto amounts yourself. ArionPay decides when an invoice is paid, including payments inside your store's payment tolerance and payments you accept in Payment Radar.
169
+
170
+ ## Test without real money
171
+
172
+ ```python
173
+ invoice = arionpay.create_invoice(amount="10", order_id="test-1", asset="USDT_TRC20", test=True)
174
+ arionpay.simulate_payment(invoice["id"], "exact") # your webhook gets invoice.paid, like a real payment
175
+ ```
176
+
177
+ Scenarios: `exact`, `detected`, `confirm`, `underpaid_1pct`, `underpaid_5pct`, `overpaid`, `partial_half`, `late`.
178
+
179
+ `arionpay.send_test_webhook("invoice.paid")` sends a signed sample event to your store's webhook address. It describes a made-up invoice (`inv_test_...`) and must never change an order.
180
+
181
+ ## Reference
182
+
183
+ | Method | Returns |
184
+ | --- | --- |
185
+ | `create_invoice(amount, currency="USD", order_id=None, ...)` | `{"id", "invoiceUrl", "status", "amountFiat", "currency", "asset", "address", "amountCrypto", "expiresAt", "orderId"}` |
186
+ | `get_invoice(invoice_id)` | The invoice, with the webhook field names. |
187
+ | `simulate_payment(invoice_id, scenario)` | Sandbox only (test invoices). |
188
+ | `send_test_webhook(event_type="invoice.paid")` | `{"delivered", "httpStatus", "eventId"}` |
189
+ | `currencies()` | Coins you can pass as `asset` / `allowed_assets`. |
190
+ | `rates(currency="USD")` | Current coin prices. |
191
+ | `verify_webhook(raw_body, signature_header)` | The event dict, or raises `SignatureError`. Also a module function taking the secret as third argument. |
192
+
193
+ `create_invoice` keyword arguments: `currency`, `order_id`, `description`, `customer_email`, `success_url`, `cancel_url`, `callback_url`, `asset`, `allowed_assets`, `expires_min` (5 to 1440), `metadata`, `idempotency_key`, `test`.
194
+
195
+ Errors are `ArionPayError` with `.status` (HTTP status, `0` when ArionPay could not be reached), `.code` (for example `idempotency_key_reused`, `rate_limited`, `unknown_asset`) and `.message`. Messages never contain your secret.
196
+
197
+ Options: `api_key`, `api_secret`, `webhook_secret`, `base_url` (default `https://merchant.arionpay.com`), `timeout` (seconds, default 20), `max_attempts` (default 3), `app_info`.
198
+
199
+ ## License
200
+
201
+ MIT
@@ -0,0 +1,181 @@
1
+ # ArionPay for Python
2
+
3
+ Official Python client for [ArionPay](https://arionpay.com). Create crypto invoices, send customers to the payment page, and check webhooks. The money goes straight to your own wallet: ArionPay never holds it.
4
+
5
+ - No dependencies (standard library only). Python 3.8 or newer.
6
+ - Works with Flask, Django, FastAPI or plain scripts.
7
+ - Safe retries: every invoice request carries an idempotency key, so a network error can never create two invoices.
8
+
9
+ ```bash
10
+ pip install arionpay
11
+ ```
12
+
13
+ ## Keys
14
+
15
+ In your ArionPay dashboard, open your store:
16
+
17
+ | Value | Where | Starts with |
18
+ | --- | --- | --- |
19
+ | API key | Store page, **API key** | `pk_` |
20
+ | API secret | Store page, **API secret** (asks for your authenticator code) | `sk_` |
21
+ | Webhook secret | **Webhooks** page, **signing secret** | `whsec_` |
22
+
23
+ Keep them on your server, for example in environment variables.
24
+
25
+ ## Take a payment
26
+
27
+ ```python
28
+ import os
29
+ from arionpay import ArionPay
30
+
31
+ arionpay = ArionPay(
32
+ api_key=os.environ["ARIONPAY_API_KEY"],
33
+ api_secret=os.environ["ARIONPAY_API_SECRET"],
34
+ webhook_secret=os.environ["ARIONPAY_WEBHOOK_SECRET"],
35
+ )
36
+
37
+ invoice = arionpay.create_invoice(
38
+ amount="49.90",
39
+ currency="USD",
40
+ order_id="1001",
41
+ success_url="https://shop.example.com/thanks/1001",
42
+ cancel_url="https://shop.example.com/cart",
43
+ metadata={"user_id": 42},
44
+ )
45
+ # send the customer to invoice["invoiceUrl"]
46
+ ```
47
+
48
+ The customer coming back to `success_url` does **not** prove they paid. Deliver the order when the `invoice.paid` webhook arrives (or when `get_invoice` says `paid`).
49
+
50
+ Invoices are returned as dicts with the same field names as the webhook's `data.invoice` (`id`, `status`, `orderId`, `amountFiat`, `currency`, `asset`, `paidCrypto`, `transactions`, `test`, `metadata`, ...), so one function can handle a webhook and a read.
51
+
52
+ ## Webhooks
53
+
54
+ Set your webhook address on the **Webhooks** page of the dashboard (a public `https://` address), or per invoice with `callback_url`. Check the signature against the **raw** body, before you parse it.
55
+
56
+ ### Flask
57
+
58
+ ```python
59
+ from flask import Flask, request
60
+ from arionpay import SignatureError, is_test_event
61
+
62
+ app = Flask(__name__)
63
+
64
+ @app.post("/arionpay/webhook")
65
+ def arionpay_webhook():
66
+ try:
67
+ event = arionpay.verify_webhook(request.get_data(), request.headers.get("ArionPay-Signature"))
68
+ except SignatureError:
69
+ return {"error": "invalid_signature"}, 401
70
+ if is_test_event(event):
71
+ return {"received": True} # "Send test webhook": not a real order
72
+ handle_event(event)
73
+ return {"received": True}
74
+ ```
75
+
76
+ ### Django
77
+
78
+ ```python
79
+ from django.http import JsonResponse
80
+ from django.views.decorators.csrf import csrf_exempt
81
+ from django.views.decorators.http import require_POST
82
+ from arionpay import SignatureError, is_test_event
83
+
84
+ @csrf_exempt
85
+ @require_POST
86
+ def arionpay_webhook(request):
87
+ try:
88
+ event = arionpay.verify_webhook(request.body, request.headers.get("ArionPay-Signature"))
89
+ except SignatureError:
90
+ return JsonResponse({"error": "invalid_signature"}, status=401)
91
+ if not is_test_event(event):
92
+ handle_event(event)
93
+ return JsonResponse({"received": True})
94
+ ```
95
+
96
+ ### FastAPI
97
+
98
+ ```python
99
+ from fastapi import FastAPI, Request, Response
100
+ from arionpay import SignatureError, is_test_event
101
+
102
+ app = FastAPI()
103
+
104
+ @app.post("/arionpay/webhook")
105
+ async def arionpay_webhook(request: Request):
106
+ raw = await request.body()
107
+ try:
108
+ event = arionpay.verify_webhook(raw, request.headers.get("arionpay-signature"))
109
+ except SignatureError:
110
+ return Response(status_code=401)
111
+ if not is_test_event(event):
112
+ handle_event(event)
113
+ return {"received": True}
114
+ ```
115
+
116
+ ### Handling an event
117
+
118
+ ```python
119
+ def handle_event(event):
120
+ if already_processed(event["id"]): # the same event can arrive more than once
121
+ return
122
+ invoice = event["data"]["invoice"]
123
+ order = find_order(invoice["orderId"])
124
+ if event["type"] == "invoice.paid" and order and not order.paid:
125
+ same_total = f"{float(order.total):.2f}" == f"{float(invoice['amountFiat']):.2f}"
126
+ if same_total and order.currency == invoice["currency"] and invoice["test"] == order.is_test:
127
+ mark_order_paid(order, invoice) # deliver here
128
+ remember_processed(event["id"])
129
+ ```
130
+
131
+ | Event | Meaning | What to do |
132
+ | --- | --- | --- |
133
+ | `invoice.pending` | A payment was seen on the network and waits for confirmations. | Show "payment on its way". Do not deliver yet. |
134
+ | `invoice.partial` | Less than the full amount arrived. The invoice stays open for the rest. | Do not deliver. |
135
+ | `invoice.paid` | Fully paid and confirmed. Also sent when you accept a payment by hand in the dashboard. | Deliver the order. |
136
+ | `invoice.expired` | Time ran out without full payment. A late payment can still make it `paid`. | Keep the order unpaid. |
137
+ | `invoice.needs_review` | Something needs a person, for example more money arrived after the invoice was paid. | Tell a human. Do not change the order. |
138
+
139
+ ArionPay sends again when your server does not answer `2xx` (for about 3 days).
140
+
141
+ ### Rules for a safe integration
142
+
143
+ 1. Check the signature on the raw body. Never trust a webhook you could not verify.
144
+ 2. Deliver only on `invoice.paid` (or `get_invoice(...)["status"] == "paid"`).
145
+ 3. Match the invoice to your order: your `order_id` or `metadata`, and the same amount and currency as the order's current total.
146
+ 4. Ignore test events (`is_test_event(event)`), and in your live shop ignore invoices with `"test": True`.
147
+ 5. Handle each `event["id"]` once, and answer `2xx` quickly.
148
+ 6. Do not compare crypto amounts yourself. ArionPay decides when an invoice is paid, including payments inside your store's payment tolerance and payments you accept in Payment Radar.
149
+
150
+ ## Test without real money
151
+
152
+ ```python
153
+ invoice = arionpay.create_invoice(amount="10", order_id="test-1", asset="USDT_TRC20", test=True)
154
+ arionpay.simulate_payment(invoice["id"], "exact") # your webhook gets invoice.paid, like a real payment
155
+ ```
156
+
157
+ Scenarios: `exact`, `detected`, `confirm`, `underpaid_1pct`, `underpaid_5pct`, `overpaid`, `partial_half`, `late`.
158
+
159
+ `arionpay.send_test_webhook("invoice.paid")` sends a signed sample event to your store's webhook address. It describes a made-up invoice (`inv_test_...`) and must never change an order.
160
+
161
+ ## Reference
162
+
163
+ | Method | Returns |
164
+ | --- | --- |
165
+ | `create_invoice(amount, currency="USD", order_id=None, ...)` | `{"id", "invoiceUrl", "status", "amountFiat", "currency", "asset", "address", "amountCrypto", "expiresAt", "orderId"}` |
166
+ | `get_invoice(invoice_id)` | The invoice, with the webhook field names. |
167
+ | `simulate_payment(invoice_id, scenario)` | Sandbox only (test invoices). |
168
+ | `send_test_webhook(event_type="invoice.paid")` | `{"delivered", "httpStatus", "eventId"}` |
169
+ | `currencies()` | Coins you can pass as `asset` / `allowed_assets`. |
170
+ | `rates(currency="USD")` | Current coin prices. |
171
+ | `verify_webhook(raw_body, signature_header)` | The event dict, or raises `SignatureError`. Also a module function taking the secret as third argument. |
172
+
173
+ `create_invoice` keyword arguments: `currency`, `order_id`, `description`, `customer_email`, `success_url`, `cancel_url`, `callback_url`, `asset`, `allowed_assets`, `expires_min` (5 to 1440), `metadata`, `idempotency_key`, `test`.
174
+
175
+ Errors are `ArionPayError` with `.status` (HTTP status, `0` when ArionPay could not be reached), `.code` (for example `idempotency_key_reused`, `rate_limited`, `unknown_asset`) and `.message`. Messages never contain your secret.
176
+
177
+ Options: `api_key`, `api_secret`, `webhook_secret`, `base_url` (default `https://merchant.arionpay.com`), `timeout` (seconds, default 20), `max_attempts` (default 3), `app_info`.
178
+
179
+ ## License
180
+
181
+ MIT
@@ -0,0 +1,33 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "arionpay"
7
+ version = "1.0.0"
8
+ description = "Official Python client for ArionPay: create crypto invoices and verify webhooks. Payments go straight to your own wallet."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ authors = [{ name = "ArionPay", email = "info@arionpay.com" }]
13
+ requires-python = ">=3.8"
14
+ dependencies = []
15
+ keywords = ["arionpay", "crypto", "payments", "bitcoin", "usdt", "payment-gateway", "webhook"]
16
+ classifiers = [
17
+ "Programming Language :: Python :: 3",
18
+ "Operating System :: OS Independent",
19
+ "Topic :: Office/Business :: Financial",
20
+ "Typing :: Typed",
21
+ ]
22
+
23
+ [project.urls]
24
+ Homepage = "https://arionpay.com"
25
+ Documentation = "https://arionpay.com/knowledge-base"
26
+ Source = "https://github.com/ArionPay-Dev/arionpay-python"
27
+ Changelog = "https://github.com/ArionPay-Dev/arionpay-python/blob/main/CHANGELOG.md"
28
+
29
+ [tool.setuptools.packages.find]
30
+ where = ["src"]
31
+
32
+ [tool.setuptools.package-data]
33
+ arionpay = ["py.typed"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,23 @@
1
+ """Official Python client for ArionPay: create crypto invoices and verify webhooks."""
2
+
3
+ from .client import DEFAULT_BASE_URL, EVENT_TYPES, SCENARIOS, VERSION, ArionPay, normalize_invoice_read
4
+ from .errors import ArionPayError, SignatureError
5
+ from .webhook import DEFAULT_TOLERANCE_SEC, is_test_event, is_valid_signature, parse_signature_header, sign_request, verify_webhook
6
+
7
+ __version__ = VERSION
8
+ __all__ = [
9
+ "ArionPay",
10
+ "ArionPayError",
11
+ "SignatureError",
12
+ "verify_webhook",
13
+ "is_valid_signature",
14
+ "is_test_event",
15
+ "parse_signature_header",
16
+ "sign_request",
17
+ "normalize_invoice_read",
18
+ "DEFAULT_BASE_URL",
19
+ "DEFAULT_TOLERANCE_SEC",
20
+ "EVENT_TYPES",
21
+ "SCENARIOS",
22
+ "VERSION",
23
+ ]