pyXRocketAPI 0.1.0__py3-none-any.whl

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,3 @@
1
+ """Public API for pyXRocketAPI."""
2
+
3
+ from .api import *
pyXRocketAPI/api.py ADDED
@@ -0,0 +1,506 @@
1
+ from collections.abc import Iterable, Mapping
2
+ from typing import Any
3
+
4
+ import requests
5
+
6
+ from .exceptions import xRocketAPIException
7
+ from .models import App, Balance, Cheque, ChequesList, Currency, Invoice, InvoicePaymentAddress, InvoicePaymentsList, InvoicesList, MassPayouts, xPage, Payout, PayoutsList, Rate, Withdrawal, WithdrawalLink, WithdrawalQuotas, WithdrawalsList, xRocketObject
8
+
9
+ PRODUCTION_API_URL = "https://pay.api.xrocket.exchange"
10
+ TESTNET_API_URL = "https://pay.api.testnet.xrocket.exchange"
11
+
12
+
13
+ def _without_none(**values: Any) -> dict[str, Any]:
14
+ """Keep valid falsey API values while omitting arguments not supplied."""
15
+ return {key: value for key, value in values.items() if value is not None}
16
+
17
+
18
+ def _identifier(first_name: str, first_value: str | None, second_name: str, second_value: str | None) -> dict[str, str]:
19
+ if first_value is None and second_value is None:
20
+ raise ValueError(f"Specify {first_name} or {second_name}.")
21
+ return _without_none(**{first_name: first_value, second_name: second_value})
22
+
23
+
24
+ class xRocketPayAPI:
25
+ """Client for the current xRocket Pay API.
26
+
27
+ Parameters
28
+ ----------
29
+ token:
30
+ App-specific Pay API Bearer token. Public calls such as
31
+ ``health_check()`` and ``get_available_currencies()`` do not require
32
+ one.
33
+ testnet:
34
+ Select the xRocket Pay testnet URL. A testnet token is required.
35
+ timeout:
36
+ Timeout passed to every request, in seconds. ``None`` uses requests'
37
+ default behaviour.
38
+ """
39
+
40
+ def __init__(
41
+ self,
42
+ token: str | None = None,
43
+ testnet: bool = False,
44
+ timeout: float | tuple[float, float] | None = 10,
45
+ ) -> None:
46
+ self.token = token
47
+ self.timeout = timeout
48
+ self.base_url = TESTNET_API_URL if testnet else PRODUCTION_API_URL
49
+
50
+ def _request(
51
+ self,
52
+ method: str,
53
+ path: str,
54
+ params: Mapping[str, Any] | None = None,
55
+ body: Mapping[str, Any] | None = None,
56
+ auth_required: bool = True,
57
+ ) -> Any:
58
+ """Send one request to the xRocket Pay REST API.
59
+
60
+ The method builds the standard ``Accept`` header, optionally adds the
61
+ application's Bearer token, sends a JSON request, and converts a
62
+ non-success response from the API's RFC 9457 Problem Details format
63
+ into :class:`xRocketAPIException`.
64
+
65
+ :param method: HTTP method, for example ``"GET"`` or ``"POST"``.
66
+ :param path: API path beginning with ``/``, appended to the selected
67
+ production or testnet base URL.
68
+ :param params: Optional query-string parameters.
69
+ :param body: Optional JSON request body.
70
+ :param auth_required: Require an API token and send it in the Bearer
71
+ header. Public endpoints pass ``False`` explicitly; rates may opt
72
+ into authorization.
73
+ :return: Parsed JSON response, or ``None`` for an empty ``204``
74
+ response.
75
+ :raises xRocketAPIException: If a required token is absent, a network
76
+ request fails, the response is not a 2xx success, or a successful
77
+ response does not contain valid JSON.
78
+ """
79
+ headers = {"Accept": "application/json"}
80
+ if auth_required:
81
+ if not self.token:
82
+ raise xRocketAPIException("This endpoint requires an xRocket Pay API token.")
83
+ headers["Authorization"] = f"Bearer {self.token}"
84
+
85
+ try:
86
+ response = requests.request(
87
+ method, f"{self.base_url}{path}", params=params, json=body, headers=headers, timeout=self.timeout
88
+ )
89
+ except requests.RequestException as error:
90
+ raise xRocketAPIException(f"Request to xRocket Pay failed: {error}") from error
91
+
92
+ if response.status_code < 200 or response.status_code >= 300:
93
+ try:
94
+ problem = response.json()
95
+ except ValueError:
96
+ problem = {}
97
+ detail = problem.get("detail") or problem.get("title") or response.text or "xRocket Pay request failed"
98
+ raise xRocketAPIException(
99
+ detail,
100
+ status=response.status_code,
101
+ problem_type=problem.get("type"),
102
+ title=problem.get("title"),
103
+ detail=problem.get("detail"),
104
+ instance=problem.get("instance"),
105
+ kind=problem.get("kind"),
106
+ info=problem.get("info"),
107
+ )
108
+
109
+ if response.status_code == 204 or not response.content:
110
+ return None
111
+ try:
112
+ return response.json()
113
+ except ValueError as error:
114
+ raise xRocketAPIException("xRocket Pay returned invalid JSON.", status=response.status_code) from error
115
+
116
+ def health_check(self) -> xRocketObject:
117
+ """Run the public health check.
118
+
119
+ API: https://docs.xrocket.exchange/api/pay/reference/http/health-controller-health
120
+
121
+ :return: ``xRocketObject``.
122
+ """
123
+ return xRocketObject.de_json(self._request("GET", "/health", auth_required=False), process_mode=2)
124
+
125
+ def get_app_info(self) -> App:
126
+ """Get information about your application.
127
+
128
+ API: https://docs.xrocket.exchange/api/pay/reference/http/app-controller-get-app
129
+
130
+ :return: ``App``.
131
+ """
132
+ return App.de_json(self._request("GET", "/api/v1/app-info"))
133
+
134
+ def get_balances(self) -> list[Balance]:
135
+ """Get balances of your application.
136
+
137
+ API: https://docs.xrocket.exchange/api/pay/reference/http/app-controller-get-app-balances
138
+
139
+ :return: ``list[Balance]``.
140
+ """
141
+ data = self._request("GET", "/api/v1/balances")
142
+ return [Balance.de_json(item) for item in data.get("balances", [])]
143
+
144
+ def get_currencies(self, kind: str | None = None) -> list[Currency]:
145
+ """Get available currencies.
146
+
147
+ API: https://docs.xrocket.exchange/api/pay/reference/http/currencies-controller-get-currencies
148
+
149
+ :param kind: No description is provided.
150
+ :return: ``list[Currency]``.
151
+ """
152
+ data = self._request(
153
+ "GET", "/api/v1/currencies", params=_without_none(kind=kind), auth_required=False
154
+ )
155
+ return [Currency.de_json(item) for item in data]
156
+
157
+ def get_rates(self, base: str, assets: Iterable[str], authorize: bool = False) -> list[Rate]:
158
+ """Get currencies rates (optional auth).
159
+
160
+ API: https://docs.xrocket.exchange/api/pay/reference/http/rate-controller-get-rates
161
+
162
+ :param base: Fiat currency.
163
+ :param assets: Asset codes.
164
+ :param authorize: Send the optional Bearer authorization header.
165
+ :return: ``list[Rate]``.
166
+ """
167
+ data = self._request(
168
+ "GET", "/api/v1/rates", params={"base": base, "assets": list(assets)},
169
+ auth_required=authorize,
170
+ )
171
+ return [Rate.de_json(item) for item in data]
172
+
173
+ def create_invoice(
174
+ self,
175
+ price_currency: str,
176
+ price_amount: str | None = None,
177
+ min_payment: str | None = None,
178
+ num_payments: int | None = None,
179
+ payout_currency: str | None = None,
180
+ pay_currencies: Iterable[str] | None = None,
181
+ client_invoice_id: str | None = None,
182
+ description: str | None = None,
183
+ expires_in: int | None = None,
184
+ callback: Mapping[str, Any] | None = None,
185
+ url: Mapping[str, Any] | None = None,
186
+ customer: Mapping[str, Any] | None = None,
187
+ is_fee_paid_by_user: bool | None = None,
188
+ data: Mapping[str, Any] | None = None,
189
+ platform_id: str | None = None,
190
+ ) -> Invoice:
191
+ """Create invoice.
192
+
193
+ API: https://docs.xrocket.exchange/api/pay/reference/http/invoice-controller-create-invoice
194
+
195
+ :param price_currency: Invoice price currency (crypto or fiat).
196
+ :param price_amount: Invoice price amount.
197
+ :param min_payment: Minimum payment amount (for open-amount invoices).
198
+ :param num_payments: Num payments for invoice.
199
+ :param payout_currency: Invoice payout crypto currency.
200
+ :param pay_currencies: Crypto currencies which can be used to pay the invoice.
201
+ :param client_invoice_id: Client Invoice ID as assigned by the client.
202
+ :param description: Description for invoice.
203
+ :param expires_in: Payment expires in milliseconds.
204
+ :param callback: Callback data.
205
+ :param url: User redirect urls.
206
+ :param customer: Customer info.
207
+ :param is_fee_paid_by_user: If true, the user pays a commission.
208
+ :param data: Custom user data passed through and returned in callbacks/webhooks (max size 4KB).
209
+ :param platform_id: Platform identifier.
210
+ :return: ``Invoice``.
211
+ """
212
+ body = _without_none(
213
+ priceCurrency=price_currency, priceAmount=price_amount, minPayment=min_payment, numPayments=num_payments,
214
+ payoutCurrency=payout_currency, payCurrencies=list(pay_currencies) if pay_currencies is not None else None,
215
+ clientInvoiceId=client_invoice_id, description=description, expiresIn=expires_in, callback=callback, url=url,
216
+ customer=customer, isFeePaidByUser=is_fee_paid_by_user, data=data, platformId=platform_id,
217
+ )
218
+ return Invoice.de_json(self._request("POST", "/api/v1/invoices", body=body))
219
+
220
+ def get_invoices_list(self, asset: str | None = None, fiat: str | None = None, ids: Iterable[str] | None = None,
221
+ status: str | None = None, cursor: str | None = None, limit: int | None = None) -> InvoicesList:
222
+ """Get list of invoices.
223
+
224
+ API: https://docs.xrocket.exchange/api/pay/reference/http/invoice-controller-get-invoices
225
+
226
+ :param asset: Filtering invoices by asset.
227
+ :param fiat: Filtering invoices by fiat.
228
+ :param ids: Filtering invoices by ids.
229
+ :param status: Filtering invoices by status.
230
+ :param cursor: Cursor for pagination.
231
+ :param limit: No description is provided.
232
+ :return: ``InvoicesList``.
233
+ """
234
+ params = _without_none(asset=asset, fiat=fiat, ids=list(ids) if ids is not None else None, status=status, cursor=cursor, limit=limit)
235
+ return InvoicesList.de_json(self._request("GET", "/api/v1/invoices", params=params))
236
+
237
+ def get_invoice_info(self, invoice_id: str | None = None, client_invoice_id: str | None = None) -> Invoice:
238
+ """Get invoice info.
239
+
240
+ API: https://docs.xrocket.exchange/api/pay/reference/http/invoice-controller-get-invoice
241
+ Either invoiceId (xRocket) or clientInvoiceId (client-assigned) is required. If both are passed, invoiceId will be used.
242
+
243
+ :param invoice_id: xRocket Invoice ID. Either invoiceId or clientInvoiceId is required. If both are passed, invoiceId will be used.
244
+ :param client_invoice_id: Client Invoice ID assigned by the client. Either invoiceId or clientInvoiceId is required.
245
+ :return: ``Invoice``.
246
+ """
247
+ return Invoice.de_json(self._request("GET", "/api/v1/invoice", params=_identifier("invoiceId", invoice_id, "clientInvoiceId", client_invoice_id)))
248
+
249
+ def delete_invoice(self, invoice_id: str | None = None, client_invoice_id: str | None = None) -> None:
250
+ """Delete invoice.
251
+
252
+ API: https://docs.xrocket.exchange/api/pay/reference/http/invoice-controller-delete-invoice
253
+ Either invoiceId (xRocket) or clientInvoiceId (client-assigned) is required. If both are passed, invoiceId will be used.
254
+
255
+ :param invoice_id: xRocket Invoice ID. Either invoiceId or clientInvoiceId is required. If both are passed, invoiceId will be used.
256
+ :param client_invoice_id: Client Invoice ID assigned by the client. Either invoiceId or clientInvoiceId is required.
257
+ :return: ``None``.
258
+ """
259
+ self._request("DELETE", "/api/v1/invoice", params=_identifier("invoiceId", invoice_id, "clientInvoiceId", client_invoice_id))
260
+
261
+ def get_invoice_payments(self, invoice_id: str | None = None, client_invoice_id: str | None = None,
262
+ cursor: str | None = None, limit: int | None = None) -> InvoicePaymentsList:
263
+ """Get invoice payments.
264
+
265
+ API: https://docs.xrocket.exchange/api/pay/reference/http/invoice-controller-get-invoice-payments
266
+ Returns payments of an invoice in the same format as the payment_status_changed webhook. Either invoiceId (xRocket) or clientInvoiceId (client-assigned) is required. If both are passed, invoiceId will be used.
267
+
268
+ :param invoice_id: xRocket Invoice ID. Either invoiceId or clientInvoiceId is required. If both are passed, invoiceId will be used.
269
+ :param client_invoice_id: Client Invoice ID assigned by the client. Either invoiceId or clientInvoiceId is required.
270
+ :param cursor: Cursor for pagination.
271
+ :param limit: No description is provided.
272
+ :return: ``InvoicePaymentsList``.
273
+ """
274
+ params = _identifier("invoiceId", invoice_id, "clientInvoiceId", client_invoice_id)
275
+ params.update(_without_none(cursor=cursor, limit=limit))
276
+ return InvoicePaymentsList.de_json(self._request("GET", "/api/v1/invoice/payments", params=params))
277
+
278
+ def create_invoice_payment_address(self, pay_network: str, invoice_id: str | None = None,
279
+ client_invoice_id: str | None = None) -> InvoicePaymentAddress:
280
+ """Create invoice payment address.
281
+
282
+ API: https://docs.xrocket.exchange/api/pay/reference/http/invoice-payment-controller-create-invoice-payment-address
283
+
284
+ :param pay_network: Network code for payment.
285
+ :param invoice_id: xRocket Invoice ID. Either invoiceId or clientInvoiceId is required. If both are passed, invoiceId will be used.
286
+ :param client_invoice_id: Client Invoice ID assigned by the client. Either invoiceId or clientInvoiceId is required.
287
+ :return: ``InvoicePaymentAddress``.
288
+ """
289
+ return InvoicePaymentAddress.de_json(self._request(
290
+ "POST", "/api/v1/invoices/payments/address",
291
+ params=_identifier("invoiceId", invoice_id, "clientInvoiceId", client_invoice_id), body={"payNetwork": pay_network},
292
+ ))
293
+
294
+ def create_cheque(self, asset: str, amount: str, client_cheque_id: str | None = None, password: str | None = None,
295
+ description: str | None = None, callback: Mapping[str, Any] | None = None, url: Mapping[str, Any] | None = None,
296
+ target_type: str | None = None, target: str | None = None) -> Cheque:
297
+ """Create cheque.
298
+
299
+ API: https://docs.xrocket.exchange/api/pay/reference/http/cheque-controller-create-cheque
300
+ Issue a personal cheque to perform an accept-type payout. The amount is reserved from the application balance and can be redeemed by the recipient or cancelled before redemption. When targetType and target are set, only the addressed user is allowed to redeem the cheque.
301
+
302
+ :param asset: Currency of transfer.
303
+ :param amount: Cheque amount.
304
+ :param client_cheque_id: Unique cheque ID in your system to prevent double spends.
305
+ :param password: Cheque password, the recipient has to enter it to redeem the cheque.
306
+ :param description: Description for cheque.
307
+ :param callback: Webhook settings for cheque activation updates.
308
+ :param url: User redirect urls after cheque activation.
309
+ :param target_type: Target type for cheque, has to be passed together with target.
310
+ :param target: Target for cheque, has to be passed together with targetType.
311
+ :return: ``Cheque``.
312
+ """
313
+ return Cheque.de_json(self._request("POST", "/api/v1/cheques", body=_without_none(
314
+ asset=asset, amount=str(amount), clientChequeId=client_cheque_id, password=password, description=description,
315
+ callback=callback, url=url, targetType=target_type, target=target,
316
+ )))
317
+
318
+ def get_cheques_list(self, from_date: str | None = None, to_date: str | None = None, target_type: str | None = None,
319
+ target: str | None = None, state: str | None = None, cursor: str | None = None, limit: int | None = None) -> ChequesList:
320
+ """Get list of cheques.
321
+
322
+ API: https://docs.xrocket.exchange/api/pay/reference/http/cheque-controller-get-cheques
323
+ List personal cheques issued for accept-type transfers. Use this to monitor pending, redeemed, or cancelled cheques. Cancelled cheques are excluded from the list.
324
+
325
+ :param from_date: From date (ISO 8601).
326
+ :param to_date: To date (ISO 8601).
327
+ :param target_type: Target type for cheque, has to be passed together with target.
328
+ :param target: Target identifier for cheque (depends on targetType), has to be passed together with targetType.
329
+ :param state: Cheque state.
330
+ :param cursor: Cursor for pagination.
331
+ :param limit: No description is provided.
332
+ :return: ``ChequesList``.
333
+ """
334
+ return ChequesList.de_json(self._request("GET", "/api/v1/cheques", params=_without_none(
335
+ fromDate=from_date, toDate=to_date, targetType=target_type, target=target, state=state, cursor=cursor, limit=limit,
336
+ )))
337
+
338
+ def get_cheque_info(self, cheque_id: str | None = None, client_cheque_id: str | None = None) -> Cheque:
339
+ """Get cheque info.
340
+
341
+ API: https://docs.xrocket.exchange/api/pay/reference/http/cheque-controller-get-cheque
342
+ Fetch details of a personal cheque used for an accept-type payout, including status and reserved amount. A cancelled cheque is returned with the deleted flag set.
343
+
344
+ :param cheque_id: Cheque id.
345
+ :param client_cheque_id: Unique cheque id in your system.
346
+ :return: ``Cheque``.
347
+ """
348
+ return Cheque.de_json(self._request("GET", "/api/v1/cheque", params=_identifier("chequeId", cheque_id, "clientChequeId", client_cheque_id)))
349
+
350
+ def update_cheque(self, description: str, cheque_id: str | None = None, client_cheque_id: str | None = None) -> Cheque:
351
+ """Update cheque.
352
+
353
+ API: https://docs.xrocket.exchange/api/pay/reference/http/cheque-controller-update-cheque
354
+ Modify an active unredeemed cheque. Only description can be updated, pass an empty string to clear it. The cheque must be in active state, not cancelled and not yet redeemed.
355
+
356
+ :param description: Cheque description (set empty string to clear description).
357
+ :param cheque_id: Cheque id.
358
+ :param client_cheque_id: Unique cheque id in your system.
359
+ :return: ``Cheque``.
360
+ """
361
+ return Cheque.de_json(self._request("PUT", "/api/v1/cheques", params=_identifier("chequeId", cheque_id, "clientChequeId", client_cheque_id), body={"description": description}))
362
+
363
+ def delete_cheque(self, cheque_id: str | None = None, client_cheque_id: str | None = None) -> None:
364
+ """Delete cheque.
365
+
366
+ API: https://docs.xrocket.exchange/api/pay/reference/http/cheque-controller-delete-cheque
367
+ Cancel an unredeemed personal cheque. Upon cancellation, the reserved funds are released back to the application balance.
368
+
369
+ :param cheque_id: Cheque id.
370
+ :param client_cheque_id: Unique cheque id in your system.
371
+ :return: ``None``.
372
+ """
373
+ self._request("DELETE", "/api/v1/cheques", params=_identifier("chequeId", cheque_id, "clientChequeId", client_cheque_id))
374
+
375
+ def payout_funds_to_user(self, target: str, target_type: str, asset: str, amount: str, client_payout_id: str | None = None,
376
+ description: str | None = None, callback: Mapping[str, Any] | None = None) -> Payout:
377
+ """Payout funds to user.
378
+
379
+ API: https://docs.xrocket.exchange/api/pay/reference/http/payout-controller-payout
380
+
381
+ :param target: Target.
382
+ :param target_type: Target type.
383
+ :param asset: Asset of transfer.
384
+ :param amount: Payout amount.
385
+ :param client_payout_id: Unique payout ID in your system to prevent double spends.
386
+ :param description: Payout description.
387
+ :param callback: Webhook settings for payout status updates.
388
+ :return: ``Payout``.
389
+ """
390
+ return Payout.de_json(self._request("POST", "/api/v1/payouts", body=_without_none(
391
+ target=target, targetType=target_type, asset=asset, amount=str(amount), clientPayoutId=client_payout_id,
392
+ description=description, callback=callback,
393
+ )))
394
+
395
+ def get_payouts_list(self, from_date: str | None = None, to_date: str | None = None, cursor: str | None = None,
396
+ limit: int | None = None) -> PayoutsList:
397
+ """Get payouts list.
398
+
399
+ API: https://docs.xrocket.exchange/api/pay/reference/http/payout-controller-get-list-payouts
400
+
401
+ :param from_date: From date (ISO 8601).
402
+ :param to_date: To date (ISO 8601).
403
+ :param cursor: Cursor for pagination.
404
+ :param limit: No description is provided.
405
+ :return: ``PayoutsList``.
406
+ """
407
+ return PayoutsList.de_json(self._request("GET", "/api/v1/payouts", params=_without_none(fromDate=from_date, toDate=to_date, cursor=cursor, limit=limit)))
408
+
409
+ def get_payout_info(self, payout_id: str | None = None, client_payout_id: str | None = None) -> Payout:
410
+ """Get payout info.
411
+
412
+ API: https://docs.xrocket.exchange/api/pay/reference/http/payout-controller-get-payout
413
+
414
+ :param payout_id: Payout ID.
415
+ :param client_payout_id: Unique payout ID in your system to prevent double spends.
416
+ :return: ``Payout``.
417
+ """
418
+ return Payout.de_json(self._request("GET", "/api/v1/payout", params=_identifier("payoutId", payout_id, "clientPayoutId", client_payout_id)))
419
+
420
+ def create_mass_payouts(self, asset: str, payouts: Iterable[Mapping[str, Any]]) -> MassPayouts:
421
+ """Create mass payouts (Telegram users only).
422
+
423
+ API: https://docs.xrocket.exchange/api/pay/reference/http/mass-payouts-controller-create-mass-payouts
424
+
425
+ :param asset: Asset of payouts.
426
+ :param payouts: List of payouts to process.
427
+ :return: ``MassPayouts``.
428
+ """
429
+ return MassPayouts.de_json(self._request("POST", "/api/v1/mass-payouts", body={"asset": asset, "payouts": list(payouts)}))
430
+
431
+ def withdrawal_funds(self, client_withdrawal_id: str, network: str, address: str, asset: str, amount: str,
432
+ comment: str | None = None, callback: Mapping[str, Any] | None = None) -> Withdrawal:
433
+ """Withdrawal funds from application to external wallet.
434
+
435
+ API: https://docs.xrocket.exchange/api/pay/reference/http/withdrawal-controller-create-withdrawal
436
+
437
+ :param client_withdrawal_id: Unique withdrawal ID in your system to prevent double spends.
438
+ :param network: Network code.
439
+ :param address: Withdrawal address.
440
+ :param asset: Asset code.
441
+ :param amount: Withdrawal amount.
442
+ :param comment: Withdrawal comment.
443
+ :param callback: Webhook settings for withdrawal status updates.
444
+ :return: ``Withdrawal``.
445
+ """
446
+ return Withdrawal.de_json(self._request("POST", "/api/v1/withdrawals", body=_without_none(
447
+ clientWithdrawalId=client_withdrawal_id, network=network, address=address, asset=asset, amount=str(amount),
448
+ comment=comment, callback=callback,
449
+ )))
450
+
451
+ def get_withdrawals_list(self, from_date: str | None = None, to_date: str | None = None, status: str | None = None,
452
+ cursor: str | None = None, limit: int | None = None) -> WithdrawalsList:
453
+ """Get application withdrawals.
454
+
455
+ API: https://docs.xrocket.exchange/api/pay/reference/http/withdrawal-controller-get-withdrawals
456
+
457
+ :param from_date: From date (ISO 8601).
458
+ :param to_date: To date (ISO 8601).
459
+ :param status: Withdrawal status.
460
+ :param cursor: Cursor for pagination.
461
+ :param limit: No description is provided.
462
+ :return: ``WithdrawalsList``.
463
+ """
464
+ return WithdrawalsList.de_json(self._request("GET", "/api/v1/withdrawals", params=_without_none(
465
+ fromDate=from_date, toDate=to_date, status=status, cursor=cursor, limit=limit,
466
+ )))
467
+
468
+ def get_withdrawal_info(self, withdrawal_id: str | None = None, client_withdrawal_id: str | None = None) -> Withdrawal:
469
+ """Get application withdrawal info.
470
+
471
+ API: https://docs.xrocket.exchange/api/pay/reference/http/withdrawal-controller-get-withdrawal
472
+
473
+ :param withdrawal_id: Withdrawal ID.
474
+ :param client_withdrawal_id: Unique withdrawal ID in your system to prevent double spends.
475
+ :return: ``Withdrawal``.
476
+ """
477
+ return Withdrawal.de_json(self._request("GET", "/api/v1/withdrawal", params=_identifier("withdrawalId", withdrawal_id, "clientWithdrawalId", client_withdrawal_id)))
478
+
479
+ def get_withdrawal_quotas(self, network: str, asset: str) -> WithdrawalQuotas:
480
+ """Get application withdrawal quotas.
481
+
482
+ API: https://docs.xrocket.exchange/api/pay/reference/http/withdrawal-controller-get-withdrawal-fees
483
+
484
+ :param network: Network code.
485
+ :param asset: Asset code.
486
+ :return: ``WithdrawalQuotas``.
487
+ """
488
+ return WithdrawalQuotas.de_json(self._request("GET", "/api/v1/withdrawal-quotas", params={"network": network, "asset": asset}))
489
+
490
+ def create_withdrawal_link(self, network: str, address: str, asset: str, amount: str, comment: str | None = None,
491
+ platform: str | None = None) -> WithdrawalLink:
492
+ """Create withdrawal link.
493
+
494
+ API: https://docs.xrocket.exchange/api/pay/reference/http/withdrawal-links-controller-create-withdrawal-link
495
+
496
+ :param network: Network code.
497
+ :param address: Withdrawal address.
498
+ :param asset: Asset code.
499
+ :param amount: Withdrawal amount.
500
+ :param comment: Withdrawal comment.
501
+ :param platform: Platform identifier (optional, use only if provided by xRocket).
502
+ :return: ``WithdrawalLink``.
503
+ """
504
+ return WithdrawalLink.de_json(self._request("POST", "/api/v1/withdrawal-link", body=_without_none(
505
+ network=network, address=address, asset=asset, amount=str(amount), comment=comment, platform=platform,
506
+ )))
@@ -0,0 +1,22 @@
1
+ class xRocketAPIException(Exception):
2
+ """An HTTP or transport failure returned while calling xRocket Pay."""
3
+
4
+ def __init__(
5
+ self,
6
+ message: str,
7
+ status: int | None = None,
8
+ problem_type: str | None = None,
9
+ title: str | None = None,
10
+ detail: str | None = None,
11
+ instance: str | None = None,
12
+ kind: str | None = None,
13
+ info: object | None = None,
14
+ ) -> None:
15
+ super().__init__(message)
16
+ self.status = status
17
+ self.problem_type = problem_type
18
+ self.title = title
19
+ self.detail = detail
20
+ self.instance = instance
21
+ self.kind = kind
22
+ self.info = info
pyXRocketAPI/models.py ADDED
@@ -0,0 +1,692 @@
1
+ import json
2
+ from abc import ABC
3
+
4
+
5
+ class xRocketObject(ABC):
6
+ """Base class for xRocket Pay API response models.
7
+
8
+ Subclasses declare their API fields in ``__init__`` and override
9
+ ``de_json`` to deserialize nested response objects where necessary.
10
+ """
11
+
12
+ @classmethod
13
+ def de_json(cls, json_dict, process_mode=0):
14
+ """Create an instance of this class from an xRocket response dictionary.
15
+
16
+ This common implementation is used by subclasses after they validate
17
+ ``json_dict`` with :meth:`check_json`.
18
+
19
+ :param json_dict: Parsed response dictionary.
20
+ :param process_mode: ``0`` returns ``None``; ``1`` creates an empty
21
+ instance; ``2`` creates an instance and fills its fields from the
22
+ response dictionary.
23
+ :return: A class instance or ``None`` when ``process_mode`` is ``0``.
24
+ """
25
+ if process_mode == 0:
26
+ return None
27
+ instance = cls()
28
+ if process_mode == 2:
29
+ for key, value in json_dict.items():
30
+ setattr(instance, key, value)
31
+ return instance
32
+
33
+ @staticmethod
34
+ def check_json(input_json, dict_copy=False):
35
+ """Validate and normalize an API response dictionary or JSON string.
36
+
37
+ :param input_json: A parsed dictionary or a JSON-formatted string.
38
+ :param dict_copy: Return a shallow copy when ``input_json`` is a
39
+ dictionary.
40
+ :return: The parsed dictionary or the original dictionary.
41
+ :raises ValueError: If the input is neither a dictionary nor a JSON
42
+ string.
43
+ """
44
+ if isinstance(input_json, dict):
45
+ return input_json.copy() if dict_copy else input_json
46
+ if isinstance(input_json, str):
47
+ return json.loads(input_json)
48
+ raise ValueError("input_json should be a JSON dictionary or string.")
49
+
50
+ def __str__(self):
51
+ """Return a readable string representation of the model fields."""
52
+ data = {}
53
+ for key, value in self.__dict__.items():
54
+ if isinstance(value, list):
55
+ data[key] = [str(item) for item in value]
56
+ elif isinstance(value, dict):
57
+ data[key] = {item_key: str(item_value) for item_key, item_value in value.items()}
58
+ elif hasattr(value, "__dict__"):
59
+ data[key] = value.__dict__
60
+ else:
61
+ data[key] = value
62
+ return str(data)
63
+
64
+
65
+ # noinspection method-overriding
66
+ class App(xRocketObject):
67
+ """Current application returned by xRocket Pay.
68
+
69
+ API: https://docs.xrocket.exchange/api/pay/reference/http/app-controller-get-app
70
+
71
+ :ivar id: No description is provided.
72
+ :ivar name: Name of current app.
73
+ """
74
+ def __init__(self):
75
+ self.id = None
76
+ self.name = None
77
+
78
+ @classmethod
79
+ def de_json(cls, json_dict):
80
+ data = cls.check_json(json_dict)
81
+ return super(App, cls).de_json(data, process_mode=2)
82
+
83
+
84
+ # noinspection method-overriding
85
+ class Balance(xRocketObject):
86
+ """Balance of an asset belonging to the current application.
87
+
88
+ API: https://docs.xrocket.exchange/api/pay/reference/http/app-controller-get-app-balances
89
+
90
+ :ivar asset: Balance asset.
91
+ :ivar balance: Asset balance.
92
+ :ivar available: Available balance.
93
+ :ivar holds: Holds balance.
94
+ """
95
+ def __init__(self):
96
+ self.asset = None
97
+ self.balance = None
98
+ self.available = None
99
+ self.holds = None
100
+
101
+ @classmethod
102
+ def de_json(cls, json_dict):
103
+ data = cls.check_json(json_dict)
104
+ return super(Balance, cls).de_json(data, process_mode=2)
105
+
106
+
107
+ # noinspection method-overriding
108
+ class InvoiceLinks(xRocketObject):
109
+ """Links used to open an invoice payment page.
110
+
111
+ API: https://docs.xrocket.exchange/api/pay/reference/http/invoice-controller-get-invoice
112
+
113
+ :ivar telegramBotLink: Invoice telegram bot link.
114
+ :ivar telegramMiniAppLink: Invoice telegram mini app link.
115
+ :ivar webLink: Invoice web link.
116
+ """
117
+ def __init__(self):
118
+ self.telegramBotLink = None
119
+ self.telegramMiniAppLink = None
120
+ self.webLink = None
121
+
122
+ @classmethod
123
+ def de_json(cls, json_dict):
124
+ data = cls.check_json(json_dict)
125
+ return super(InvoiceLinks, cls).de_json(data, process_mode=2)
126
+
127
+
128
+ # noinspection method-overriding
129
+ class Invoice(xRocketObject):
130
+ """Invoice created in xRocket Pay.
131
+
132
+ API: https://docs.xrocket.exchange/api/pay/reference/http/invoice-controller-get-invoice
133
+
134
+ :ivar id: Invoice id.
135
+ :ivar priceAmount: Invoice price amount.
136
+ :ivar minPayment: Minimum payment amount (for open-amount invoices).
137
+ :ivar priceCurrency: Invoice price currency (crypto or fiat).
138
+ :ivar payCurrencies: Currencies which can be used to pay the invoice (crypto or fiat).
139
+ :ivar clientInvoiceId: Your unique identifier for this invoice to link with your internal system (e.g., order ID).
140
+ :ivar description: Description for invoice.
141
+ :ivar expiresIn: Invoice expires in milliseconds (from creation time).
142
+ :ivar createdAt: Invoice creation time.
143
+ :ivar expiresAt: Invoice expiration time (null if no expiration).
144
+ :ivar status: Invoice status. **WARNING**: This list may be extended in the future. Always use exact status comparison and handle unknown statuses gracefully.
145
+ :ivar callback: No description is provided.
146
+ :ivar url: No description is provided.
147
+ :ivar customer: No description is provided.
148
+ :ivar links: No description is provided.
149
+ """
150
+ def __init__(self):
151
+ self.id = None
152
+ self.priceAmount = None
153
+ self.minPayment = None
154
+ self.priceCurrency = None
155
+ self.payCurrencies = []
156
+ self.clientInvoiceId = None
157
+ self.description = None
158
+ self.expiresIn = None
159
+ self.createdAt = None
160
+ self.expiresAt = None
161
+ self.status = None
162
+ self.callback = None
163
+ self.url = None
164
+ self.customer = None
165
+ self.links = None
166
+
167
+ @classmethod
168
+ def de_json(cls, json_dict):
169
+ data = cls.check_json(json_dict)
170
+ instance = super(Invoice, cls).de_json(data, process_mode=2)
171
+ if instance.links is not None:
172
+ instance.links = InvoiceLinks.de_json(instance.links)
173
+ return instance
174
+
175
+
176
+ # noinspection method-overriding
177
+ class ChequeLinks(xRocketObject):
178
+ """Links used to activate a cheque.
179
+
180
+ API: https://docs.xrocket.exchange/api/pay/reference/http/cheque-controller-get-cheque
181
+
182
+ :ivar telegramBotLink: Cheque activation telegram bot link.
183
+ :ivar telegramMiniAppLink: Cheque activation telegram mini app link (soon).
184
+ :ivar webLink: Cheque activation web link (soon).
185
+ """
186
+ def __init__(self):
187
+ self.telegramBotLink = None
188
+ self.telegramMiniAppLink = None
189
+ self.webLink = None
190
+
191
+ @classmethod
192
+ def de_json(cls, json_dict):
193
+ data = cls.check_json(json_dict)
194
+ return super(ChequeLinks, cls).de_json(data, process_mode=2)
195
+
196
+
197
+ # noinspection method-overriding
198
+ class Cheque(xRocketObject):
199
+ """Cheque created in xRocket Pay.
200
+
201
+ API: https://docs.xrocket.exchange/api/pay/reference/http/cheque-controller-get-cheque
202
+
203
+ :ivar chequeId: Cheque ID.
204
+ :ivar clientChequeId: Unique cheque ID in your system to prevent double spends.
205
+ :ivar asset: Currency of transfer.
206
+ :ivar description: Description for cheque.
207
+ :ivar targetType: Target type for cheque.
208
+ :ivar target: Target for cheque.
209
+ :ivar links: Cheque activation links.
210
+ :ivar state: Cheque state.
211
+ :ivar deleted: Cheque is cancelled and the reserved funds are returned to the application balance.
212
+ :ivar callback: No description is provided.
213
+ :ivar url: No description is provided.
214
+ """
215
+ def __init__(self):
216
+ self.chequeId = None
217
+ self.clientChequeId = None
218
+ self.asset = None
219
+ self.description = None
220
+ self.targetType = None
221
+ self.target = None
222
+ self.links = None
223
+ self.state = None
224
+ self.deleted = None
225
+ self.callback = None
226
+ self.url = None
227
+
228
+ @classmethod
229
+ def de_json(cls, json_dict):
230
+ data = cls.check_json(json_dict)
231
+ instance = super(Cheque, cls).de_json(data, process_mode=2)
232
+ if instance.links is not None:
233
+ instance.links = ChequeLinks.de_json(instance.links)
234
+ return instance
235
+
236
+
237
+ # noinspection method-overriding
238
+ class Payout(xRocketObject):
239
+ """Payout from the current application to a user.
240
+
241
+ API: https://docs.xrocket.exchange/api/pay/reference/http/payout-controller-get-payout
242
+
243
+ :ivar payoutId: Payout ID.
244
+ :ivar clientPayoutId: Unique payout ID in your system to prevent double spends.
245
+ :ivar target: Target.
246
+ :ivar targetType: Target type.
247
+ :ivar asset: Asset of payout.
248
+ :ivar amount: Payout amount.
249
+ :ivar description: Payout description.
250
+ :ivar status: Payout status.
251
+ :ivar callback: Webhook settings of this payout.
252
+ """
253
+ def __init__(self):
254
+ self.payoutId = None
255
+ self.clientPayoutId = None
256
+ self.target = None
257
+ self.targetType = None
258
+ self.asset = None
259
+ self.amount = None
260
+ self.description = None
261
+ self.status = None
262
+ self.callback = None
263
+
264
+ @classmethod
265
+ def de_json(cls, json_dict):
266
+ data = cls.check_json(json_dict)
267
+ return super(Payout, cls).de_json(data, process_mode=2)
268
+
269
+
270
+ # noinspection method-overriding
271
+ class Withdrawal(xRocketObject):
272
+ """Withdrawal from the current application to an external wallet.
273
+
274
+ API: https://docs.xrocket.exchange/api/pay/reference/http/withdrawal-controller-get-withdrawal
275
+
276
+ :ivar withdrawalId: Unique withdrawal ID in your system to prevent double spends.
277
+ :ivar network: Network code.
278
+ :ivar address: Withdrawal address.
279
+ :ivar asset: Asset code.
280
+ :ivar amount: Withdrawal amount. 9 decimal places, others cut off.
281
+ :ivar status: Withdrawal status.
282
+ :ivar comment: Withdrawal comment.
283
+ :ivar txHash: Withdrawal TX hash. Provided only after withdrawal.
284
+ :ivar txLink: Withdrawal TX link. Provided only after withdrawal.
285
+ :ivar callback: Webhook settings of this withdrawal.
286
+ """
287
+ def __init__(self):
288
+ self.withdrawalId = None
289
+ self.network = None
290
+ self.address = None
291
+ self.asset = None
292
+ self.amount = None
293
+ self.status = None
294
+ self.comment = None
295
+ self.txHash = None
296
+ self.txLink = None
297
+ self.callback = None
298
+
299
+ @classmethod
300
+ def de_json(cls, json_dict):
301
+ data = cls.check_json(json_dict)
302
+ return super(Withdrawal, cls).de_json(data, process_mode=2)
303
+
304
+
305
+ # noinspection method-overriding
306
+ class CurrencyNetwork(xRocketObject):
307
+ """Network supported by a currency.
308
+
309
+ API: https://docs.xrocket.exchange/api/pay/reference/http/currencies-controller-get-currencies
310
+
311
+ :ivar code: Network code.
312
+ """
313
+ def __init__(self):
314
+ self.code = None
315
+
316
+ @classmethod
317
+ def de_json(cls, json_dict):
318
+ data = cls.check_json(json_dict)
319
+ return super(CurrencyNetwork, cls).de_json(data, process_mode=2)
320
+
321
+
322
+ # noinspection method-overriding
323
+ class Currency(xRocketObject):
324
+ """Currency available in xRocket Pay.
325
+
326
+ API: https://docs.xrocket.exchange/api/pay/reference/http/currencies-controller-get-currencies
327
+
328
+ :ivar code: No description is provided.
329
+ :ivar title: No description is provided.
330
+ :ivar kind: No description is provided.
331
+ :ivar networks: No description is provided.
332
+ """
333
+ def __init__(self):
334
+ self.code = None
335
+ self.title = None
336
+ self.kind = None
337
+ self.networks = []
338
+
339
+ @classmethod
340
+ def de_json(cls, json_dict):
341
+ data = cls.check_json(json_dict)
342
+ instance = super(Currency, cls).de_json(data, process_mode=2)
343
+ instance.networks = [CurrencyNetwork.de_json(item) for item in instance.networks]
344
+ return instance
345
+
346
+
347
+ # noinspection method-overriding
348
+ class Rate(xRocketObject):
349
+ """Current exchange rate for a currency.
350
+
351
+ API: https://docs.xrocket.exchange/api/pay/reference/http/rate-controller-get-rates
352
+
353
+ :ivar currency: No description is provided.
354
+ :ivar rate: Current rate.
355
+ """
356
+ def __init__(self):
357
+ self.currency = None
358
+ self.rate = None
359
+
360
+ @classmethod
361
+ def de_json(cls, json_dict):
362
+ data = cls.check_json(json_dict)
363
+ return super(Rate, cls).de_json(data, process_mode=2)
364
+
365
+
366
+ # noinspection method-overriding
367
+ class xPage(xRocketObject):
368
+ """Base class for paginated xRocket Pay responses.
369
+
370
+ This is an SDK base model; the API has no standalone page endpoint.
371
+
372
+ :ivar items: No description is provided.
373
+ :ivar pagination: No description is provided.
374
+ """
375
+ def __init__(self):
376
+ self.items = []
377
+ self.pagination = None
378
+
379
+ @classmethod
380
+ def de_json(cls, json_dict, process_mode=None):
381
+ data = cls.check_json(json_dict)
382
+ return super(xPage, cls).de_json(data, process_mode=2 if process_mode is None else process_mode)
383
+
384
+
385
+ # noinspection method-overriding
386
+ class CursorPagination(xRocketObject):
387
+ """Cursor pagination information for list responses.
388
+
389
+ This shared response fragment has no standalone API endpoint.
390
+
391
+ :ivar total: Total quantity of campaigns.
392
+ :ivar next: Cursor for the next page of results.
393
+ """
394
+ def __init__(self):
395
+ self.total = None
396
+ self.next = None
397
+
398
+ @classmethod
399
+ def de_json(cls, json_dict):
400
+ data = cls.check_json(json_dict)
401
+ return super(CursorPagination, cls).de_json(data, process_mode=2)
402
+
403
+
404
+ # noinspection method-overriding
405
+ class InvoicePaymentsPagination(xRocketObject):
406
+ """Cursor pagination information for invoice-payment lists.
407
+
408
+ API: https://docs.xrocket.exchange/api/pay/reference/http/invoice-controller-get-invoice-payments
409
+
410
+ :ivar next: Cursor for the next page of results.
411
+ """
412
+ def __init__(self):
413
+ self.next = None
414
+
415
+ @classmethod
416
+ def de_json(cls, json_dict):
417
+ data = cls.check_json(json_dict)
418
+ return super(InvoicePaymentsPagination, cls).de_json(data, process_mode=2)
419
+
420
+
421
+ # noinspection method-overriding
422
+ class InvoicePayment(xRocketObject):
423
+ """A payment made for an invoice.
424
+
425
+ API: https://docs.xrocket.exchange/api/pay/reference/http/invoice-controller-get-invoice-payments
426
+
427
+ :ivar id: Unique payment id. Use it to match webhook events with the invoice payments endpoint.
428
+ :ivar status: Invoice status. **WARNING**: This list may be extended in the future. Always use exact status comparison and handle unknown statuses gracefully.
429
+ :ivar finalizedAt: When payment reached final state (null for in-progress payments).
430
+ :ivar payAmount: Gross amount payer sent in total across all transactions of this payment (before fees).
431
+ :ivar payCurrency: Currency payer used.
432
+ :ivar receiveAmount: Net amount merchant receives after fees, summed across all transactions of this payment (in invoice priceCurrency).
433
+ :ivar receiveCurrency: Currency merchant receives (= invoice priceCurrency).
434
+ :ivar transactions: No description is provided.
435
+ """
436
+ def __init__(self):
437
+ self.id = None
438
+ self.status = None
439
+ self.finalizedAt = None
440
+ self.payAmount = None
441
+ self.payCurrency = None
442
+ self.receiveAmount = None
443
+ self.receiveCurrency = None
444
+ self.transactions = []
445
+
446
+ @classmethod
447
+ def de_json(cls, json_dict):
448
+ data = cls.check_json(json_dict)
449
+ return super(InvoicePayment, cls).de_json(data, process_mode=2)
450
+
451
+
452
+ # noinspection method-overriding
453
+ class InvoicesList(xPage):
454
+ """Paginated list of invoices.
455
+
456
+ API: https://docs.xrocket.exchange/api/pay/reference/http/invoice-controller-get-invoices
457
+
458
+ :ivar items: No description is provided.
459
+ :ivar pagination: No description is provided.
460
+ """
461
+ @classmethod
462
+ def de_json(cls, json_dict):
463
+ data = cls.check_json(json_dict)
464
+ instance = super(InvoicesList, cls).de_json(data)
465
+ instance.items = [Invoice.de_json(item) for item in instance.items]
466
+ if instance.pagination is not None:
467
+ instance.pagination = CursorPagination.de_json(instance.pagination)
468
+ return instance
469
+
470
+
471
+ # noinspection method-overriding
472
+ class InvoicePaymentsList(xPage):
473
+ """Paginated list of invoice payments.
474
+
475
+ API: https://docs.xrocket.exchange/api/pay/reference/http/invoice-controller-get-invoice-payments
476
+
477
+ :ivar items: No description is provided.
478
+ :ivar pagination: No description is provided.
479
+ """
480
+ @classmethod
481
+ def de_json(cls, json_dict):
482
+ data = cls.check_json(json_dict)
483
+ instance = super(InvoicePaymentsList, cls).de_json(data)
484
+ instance.items = [InvoicePayment.de_json(item) for item in instance.items]
485
+ if instance.pagination is not None:
486
+ instance.pagination = InvoicePaymentsPagination.de_json(instance.pagination)
487
+ return instance
488
+
489
+
490
+ # noinspection method-overriding
491
+ class ChequesList(xPage):
492
+ """Paginated list of cheques.
493
+
494
+ API: https://docs.xrocket.exchange/api/pay/reference/http/cheque-controller-get-cheques
495
+
496
+ :ivar items: No description is provided.
497
+ :ivar pagination: No description is provided.
498
+ """
499
+ @classmethod
500
+ def de_json(cls, json_dict):
501
+ data = cls.check_json(json_dict)
502
+ instance = super(ChequesList, cls).de_json(data)
503
+ instance.items = [Cheque.de_json(item) for item in instance.items]
504
+ if instance.pagination is not None:
505
+ instance.pagination = CursorPagination.de_json(instance.pagination)
506
+ return instance
507
+
508
+
509
+ # noinspection method-overriding
510
+ class PayoutsList(xPage):
511
+ """Paginated list of payouts.
512
+
513
+ API: https://docs.xrocket.exchange/api/pay/reference/http/payout-controller-get-list-payouts
514
+
515
+ :ivar items: No description is provided.
516
+ :ivar pagination: No description is provided.
517
+ """
518
+ @classmethod
519
+ def de_json(cls, json_dict):
520
+ data = cls.check_json(json_dict)
521
+ instance = super(PayoutsList, cls).de_json(data)
522
+ instance.items = [Payout.de_json(item) for item in instance.items]
523
+ if instance.pagination is not None:
524
+ instance.pagination = CursorPagination.de_json(instance.pagination)
525
+ return instance
526
+
527
+
528
+ # noinspection method-overriding
529
+ class WithdrawalsList(xPage):
530
+ """Paginated list of withdrawals.
531
+
532
+ API: https://docs.xrocket.exchange/api/pay/reference/http/withdrawal-controller-get-withdrawals
533
+
534
+ :ivar items: No description is provided.
535
+ :ivar pagination: No description is provided.
536
+ """
537
+ @classmethod
538
+ def de_json(cls, json_dict):
539
+ data = cls.check_json(json_dict)
540
+ instance = super(WithdrawalsList, cls).de_json(data)
541
+ instance.items = [Withdrawal.de_json(item) for item in instance.items]
542
+ if instance.pagination is not None:
543
+ instance.pagination = CursorPagination.de_json(instance.pagination)
544
+ return instance
545
+
546
+
547
+ # noinspection method-overriding
548
+ class InvoicePaymentAddress(xRocketObject):
549
+ """Deposit address created for an invoice payment.
550
+
551
+ API: https://docs.xrocket.exchange/api/pay/reference/http/invoice-payment-controller-create-invoice-payment-address
552
+
553
+ :ivar address: Deposit address.
554
+ :ivar payCurrency: Currency code.
555
+ :ivar payNetwork: Network code.
556
+ :ivar expiresAt: Payment expired at.
557
+ :ivar minAmount: Minimum deposit amount (invoice has no fixed amount).
558
+ """
559
+ def __init__(self):
560
+ self.address = None
561
+ self.payCurrency = None
562
+ self.payNetwork = None
563
+ self.expiresAt = None
564
+ self.minAmount = None
565
+
566
+ @classmethod
567
+ def de_json(cls, json_dict):
568
+ data = cls.check_json(json_dict)
569
+ return super(InvoicePaymentAddress, cls).de_json(data, process_mode=2)
570
+
571
+
572
+ # noinspection method-overriding
573
+ class WithdrawalQuotas(xRocketObject):
574
+ """Withdrawal quotas for an asset and network.
575
+
576
+ API: https://docs.xrocket.exchange/api/pay/reference/http/withdrawal-controller-get-withdrawal-fees
577
+
578
+ :ivar withdrawMinSize: Minimum withdrawal amount.
579
+ :ivar withdrawFee: Withdrawal fee.
580
+ :ivar withdrawFeeAsset: Withdrawal fee asset.
581
+ :ivar precision: Floating point precision.
582
+ """
583
+ def __init__(self):
584
+ self.withdrawMinSize = None
585
+ self.withdrawFee = None
586
+ self.withdrawFeeAsset = None
587
+ self.precision = None
588
+
589
+ @classmethod
590
+ def de_json(cls, json_dict):
591
+ data = cls.check_json(json_dict)
592
+ return super(WithdrawalQuotas, cls).de_json(data, process_mode=2)
593
+
594
+
595
+ # noinspection method-overriding
596
+ class WithdrawalLink(xRocketObject):
597
+ """Links used to create a withdrawal from a user.
598
+
599
+ API: https://docs.xrocket.exchange/api/pay/reference/http/withdrawal-links-controller-create-withdrawal-link
600
+
601
+ :ivar telegramBotLink: Withdrawal telegram bot link.
602
+ :ivar telegramMiniAppLink: Withdrawal telegram mini app link (soon).
603
+ :ivar webLink: Withdrawal web link (soon).
604
+ """
605
+ def __init__(self):
606
+ self.telegramBotLink = None
607
+ self.telegramMiniAppLink = None
608
+ self.webLink = None
609
+
610
+ @classmethod
611
+ def de_json(cls, json_dict):
612
+ data = cls.check_json(json_dict)
613
+ return super(WithdrawalLink, cls).de_json(data, process_mode=2)
614
+
615
+
616
+ # noinspection method-overriding
617
+ class MassPayoutReason(xRocketObject):
618
+ """Problem details for one failed mass payout.
619
+
620
+ API: https://docs.xrocket.exchange/api/pay/reference/http/mass-payouts-controller-create-mass-payouts
621
+
622
+ :ivar type: A URI reference that identifies the problem type.
623
+ :ivar title: A short, human-readable summary of the problem type.
624
+ :ivar status: HTTP status code.
625
+ :ivar detail: A human-readable explanation specific to this occurrence of the problem.
626
+ :ivar instance: A URI reference that identifies the specific occurrence of the problem.
627
+ :ivar kind: Problem category for easier error handling.
628
+ """
629
+ def __init__(self):
630
+ self.type = None
631
+ self.title = None
632
+ self.status = None
633
+ self.detail = None
634
+ self.instance = None
635
+ self.kind = None
636
+
637
+ @classmethod
638
+ def de_json(cls, json_dict):
639
+ data = cls.check_json(json_dict)
640
+ return super(MassPayoutReason, cls).de_json(data, process_mode=2)
641
+
642
+
643
+ # noinspection method-overriding
644
+ class MassPayoutError(xRocketObject):
645
+ """A failed payout returned by a mass-payout request.
646
+
647
+ API: https://docs.xrocket.exchange/api/pay/reference/http/mass-payouts-controller-create-mass-payouts
648
+
649
+ :ivar target: Target.
650
+ :ivar targetType: Target type (only TelegramUserId is supported for mass payouts).
651
+ :ivar amount: Payout amount.
652
+ :ivar clientPayoutId: Unique payout ID in your system to prevent double spends.
653
+ :ivar description: Payout description.
654
+ :ivar reason: Payout error reason.
655
+ """
656
+ def __init__(self):
657
+ self.target = None
658
+ self.targetType = None
659
+ self.amount = None
660
+ self.clientPayoutId = None
661
+ self.description = None
662
+ self.reason = None
663
+
664
+ @classmethod
665
+ def de_json(cls, json_dict):
666
+ data = cls.check_json(json_dict)
667
+ instance = super(MassPayoutError, cls).de_json(data, process_mode=2)
668
+ if instance.reason is not None:
669
+ instance.reason = MassPayoutReason.de_json(instance.reason)
670
+ return instance
671
+
672
+
673
+ # noinspection method-overriding
674
+ class MassPayouts(xRocketObject):
675
+ """Result of a mass-payout request.
676
+
677
+ API: https://docs.xrocket.exchange/api/pay/reference/http/mass-payouts-controller-create-mass-payouts
678
+
679
+ :ivar successPayouts: Successful payouts.
680
+ :ivar errorPayouts: Error payouts.
681
+ """
682
+ def __init__(self):
683
+ self.successPayouts = []
684
+ self.errorPayouts = []
685
+
686
+ @classmethod
687
+ def de_json(cls, json_dict):
688
+ data = cls.check_json(json_dict)
689
+ instance = super(MassPayouts, cls).de_json(data, process_mode=2)
690
+ instance.successPayouts = [Payout.de_json(item) for item in instance.successPayouts]
691
+ instance.errorPayouts = [MassPayoutError.de_json(item) for item in instance.errorPayouts]
692
+ return instance
@@ -0,0 +1,3 @@
1
+ """Package version, read by the build configuration."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,52 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyXRocketAPI
3
+ Version: 0.1.0
4
+ Summary: Python client for the xRocket Pay API
5
+ Author: Badiboy
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Badiboy/pyXRocketAPI
8
+ Project-URL: Documentation, https://docs.xrocket.exchange/api/pay/pay-api-overview
9
+ Project-URL: Repository, https://github.com/Badiboy/pyXRocketAPI
10
+ Keywords: xrocket,pay,crypto,payments,api
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: requests>=2.28
18
+ Dynamic: license-file
19
+
20
+ # pyXRocketAPI
21
+
22
+ **pyXRocketAPI** is a Python client for the [xRocket Pay API](https://docs.xrocket.exchange/api/pay/pay-api-overview). It supports application information, balances, invoices, cheques, payouts, withdrawals, currency rates, and health checks.
23
+
24
+ ## Installation
25
+
26
+ ```shell
27
+ pip install pyXRocketAPI
28
+ ```
29
+
30
+ ## Quick start
31
+
32
+ ```python
33
+ from pyXRocketAPI import xRocketPayAPI
34
+
35
+ client = xRocketPayAPI(token="your-pay-api-token")
36
+ invoice = client.create_invoice(price_currency="USDT", price_amount="10.00")
37
+ print(invoice.id, invoice.links.web_link)
38
+ ```
39
+
40
+ For integration testing, use the xRocket testnet instead of production:
41
+
42
+ ```python
43
+ client = xRocketPayAPI(token="testnet-token", testnet=True)
44
+ ```
45
+
46
+ ## Safety
47
+
48
+ The token grants access to the application and must not be committed to source control. Financial POST operations are not retried automatically. Supply and retain the relevant client identifier (`client_invoice_id`, `client_payout_id`, `client_cheque_id`, or `client_withdrawal_id`) so that a timed-out operation can be reconciled safely.
49
+
50
+ Errors from the API raise `xRocketAPIException`; its `problem_type`, `kind`, `status`, and `instance` attributes expose the RFC 9457 error response.
51
+
52
+ _AI-supported creation._
@@ -0,0 +1,10 @@
1
+ pyXRocketAPI/__init__.py,sha256=yihLUNgpvxfUS1eSXXpE33IYdGGc_sxI7G-DyfTRsBs,55
2
+ pyXRocketAPI/api.py,sha256=5LJJf5q3o1xJS5uIRJrMQ-VQ_o-q5jWVtsnPqvkuW1M,26164
3
+ pyXRocketAPI/exceptions.py,sha256=H-L4mJA-BgvwCBqh_TSvP5qTABtJe4RtDkZ5lix60og,677
4
+ pyXRocketAPI/models.py,sha256=gpVp75FpSA5GXCWgTYhwiseWceAwpHj3dyh0X3GB5DQ,24041
5
+ pyXRocketAPI/version.py,sha256=udWknsv3LDLQEwP4_UQUQeRp1okJILh9rKefhiqdBl4,79
6
+ pyxrocketapi-0.1.0.dist-info/licenses/LICENSE,sha256=iw-28FPO0DiYiTwy8rfgljZxjhA12F5hhqHe_BpYW-o,1064
7
+ pyxrocketapi-0.1.0.dist-info/METADATA,sha256=FLnuVcbfbGDWeJnCL4LEsB1L8yREeudgNC-I8ouDZlk,1965
8
+ pyxrocketapi-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
9
+ pyxrocketapi-0.1.0.dist-info/top_level.txt,sha256=33Ju2GBtWw8-eJeVkNtL7TR1g7SV-g9_3dw_Y56KvmU,13
10
+ pyxrocketapi-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Badiboy
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 @@
1
+ pyXRocketAPI